From 92b78f7c152eda35970bb139c212dfa6ead8ac09 Mon Sep 17 00:00:00 2001 From: Clement Michaud Date: Sun, 15 Oct 2017 16:34:39 +0200 Subject: [PATCH 1/4] Enable secure and httpOnly option for sessions These are 2 measures for improving security of cookies. One is used to not send the cookie over HTTP (only HTTPS) and the other tells the browser to disallow client-side code accessing the cookie. --- docker-compose.yml | 2 ++ example/authelia/docker-compose.yml | 2 ++ example/nginx/nginx.conf | 6 ++++++ server/src/index.ts | 2 -- server/src/lib/Server.ts | 6 +++--- server/src/lib/configuration/SessionConfigurationBuilder.ts | 3 ++- server/test/SessionConfigurationBuilder.test.ts | 6 ++++-- 7 files changed, 19 insertions(+), 8 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 3c8717131..a76ee46ea 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,6 +5,8 @@ services: restart: always volumes: - ./config.template.yml:/etc/authelia/config.yml:ro + environment: + - NODE_TLS_REJECT_UNAUTHORIZED=0 depends_on: - redis networks: diff --git a/example/authelia/docker-compose.yml b/example/authelia/docker-compose.yml index 9f1f1cb5d..7c68dec9a 100644 --- a/example/authelia/docker-compose.yml +++ b/example/authelia/docker-compose.yml @@ -6,6 +6,8 @@ services: volumes: - ./config.template.yml:/etc/authelia/config.yml:ro - ./notifications:/var/lib/authelia/notifications + environment: + - NODE_TLS_REJECT_UNAUTHORIZED=0 depends_on: - redis networks: diff --git a/example/nginx/nginx.conf b/example/nginx/nginx.conf index a1ec3dbc2..5e8a0496b 100644 --- a/example/nginx/nginx.conf +++ b/example/nginx/nginx.conf @@ -35,6 +35,7 @@ http { proxy_set_header X-Original-URI $request_uri; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://authelia/; @@ -73,6 +74,7 @@ http { internal; proxy_set_header X-Original-URI $request_uri; proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $http_host; proxy_set_header Content-Length ""; @@ -126,6 +128,7 @@ http { internal; proxy_set_header X-Original-URI $request_uri; proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $http_host; proxy_set_header Content-Length ""; @@ -162,6 +165,7 @@ http { internal; proxy_set_header X-Original-URI $request_uri; proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $http_host; proxy_set_header Content-Length ""; @@ -198,6 +202,7 @@ http { internal; proxy_set_header X-Original-URI $request_uri; proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $http_host; proxy_set_header Content-Length ""; @@ -234,6 +239,7 @@ http { internal; proxy_set_header X-Original-URI $request_uri; proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $http_host; proxy_set_header Content-Length ""; diff --git a/server/src/index.ts b/server/src/index.ts index b5a20ac52..429cc8578 100755 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -1,7 +1,5 @@ #! /usr/bin/env node -process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; - import Server from "./lib/Server"; import { GlobalDependencies } from "../types/Dependencies"; import YAML = require("yamljs"); diff --git a/server/src/lib/Server.ts b/server/src/lib/Server.ts index 5d80e3322..f043d4f33 100644 --- a/server/src/lib/Server.ts +++ b/server/src/lib/Server.ts @@ -23,8 +23,8 @@ import * as http from "http"; const addRequestId = require("express-request-id")(); // Constants - const TRUST_PROXY = "trust proxy"; +const X_POWERED_BY = "x-powered-by"; const VIEWS = "views"; const VIEW_ENGINE = "view engine"; const PUG = "pug"; @@ -54,9 +54,9 @@ export default class Server { app.use(BodyParser.json()); app.use(deps.session(expressSessionOptions)); app.use(addRequestId); - app.disable("x-powered-by"); + app.disable(X_POWERED_BY); + app.enable(TRUST_PROXY); - app.set(TRUST_PROXY, 1); app.set(VIEWS, viewsDirectory); app.set(VIEW_ENGINE, PUG); diff --git a/server/src/lib/configuration/SessionConfigurationBuilder.ts b/server/src/lib/configuration/SessionConfigurationBuilder.ts index 3560cbb2b..bee21c764 100644 --- a/server/src/lib/configuration/SessionConfigurationBuilder.ts +++ b/server/src/lib/configuration/SessionConfigurationBuilder.ts @@ -12,7 +12,8 @@ export class SessionConfigurationBuilder { resave: false, saveUninitialized: true, cookie: { - secure: false, + secure: true, + httpOnly: true, maxAge: configuration.session.expiration, domain: configuration.session.domain }, diff --git a/server/test/SessionConfigurationBuilder.test.ts b/server/test/SessionConfigurationBuilder.test.ts index bae332347..c5a8cd91d 100644 --- a/server/test/SessionConfigurationBuilder.test.ts +++ b/server/test/SessionConfigurationBuilder.test.ts @@ -73,7 +73,8 @@ describe("test session configuration builder", function () { resave: false, saveUninitialized: true, cookie: { - secure: false, + secure: true, + httpOnly: true, maxAge: 3600, domain: "example.com" } @@ -153,7 +154,8 @@ describe("test session configuration builder", function () { resave: false, saveUninitialized: true, cookie: { - secure: false, + secure: true, + httpOnly: true, maxAge: 3600, domain: "example.com" }, From f523e5335f7f6bf95d6174039cb512aeca75af65 Mon Sep 17 00:00:00 2001 From: Clement Michaud Date: Sun, 15 Oct 2017 17:18:15 +0200 Subject: [PATCH 2/4] Use HSTS in example --- example/nginx/nginx.conf | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/example/nginx/nginx.conf b/example/nginx/nginx.conf index 5e8a0496b..5c2150253 100644 --- a/example/nginx/nginx.conf +++ b/example/nginx/nginx.conf @@ -30,6 +30,7 @@ http { ssl_certificate /etc/ssl/server.crt; ssl_certificate_key /etc/ssl/server.key; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; location / { proxy_set_header X-Original-URI $request_uri; @@ -58,6 +59,8 @@ http { ssl on; ssl_certificate /etc/ssl/server.crt; ssl_certificate_key /etc/ssl/server.key; + + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; } server { @@ -70,6 +73,8 @@ http { ssl_certificate /etc/ssl/server.crt; ssl_certificate_key /etc/ssl/server.key; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + location /auth_verify { internal; proxy_set_header X-Original-URI $request_uri; @@ -124,6 +129,8 @@ http { ssl_certificate /etc/ssl/server.crt; ssl_certificate_key /etc/ssl/server.key; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + location /auth_verify { internal; proxy_set_header X-Original-URI $request_uri; @@ -161,6 +168,8 @@ http { ssl_certificate /etc/ssl/server.crt; ssl_certificate_key /etc/ssl/server.key; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + location /auth_verify { internal; proxy_set_header X-Original-URI $request_uri; @@ -198,6 +207,8 @@ http { ssl_certificate /etc/ssl/server.crt; ssl_certificate_key /etc/ssl/server.key; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + location /auth_verify { internal; proxy_set_header X-Original-URI $request_uri; @@ -235,6 +246,8 @@ http { ssl_certificate /etc/ssl/server.crt; ssl_certificate_key /etc/ssl/server.key; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + location /auth_verify { internal; proxy_set_header X-Original-URI $request_uri; From 0b33982701132399da9b0899e9efd47aab2abcf0 Mon Sep 17 00:00:00 2001 From: Clement Michaud Date: Sun, 15 Oct 2017 17:57:12 +0200 Subject: [PATCH 3/4] Add notes on security measures deployed in Authelia in README --- README.md | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7049052dd..2554719fd 100644 --- a/README.md +++ b/README.md @@ -24,11 +24,12 @@ used in production to secure internal services in a small docker swarm cluster. 5. [Access control](#access-control) 6. [Basic authentication](#basic-authentication) 7. [Session management with Redis](#session-management-with-redis) -4. [Documentation](#documentation) +4. [Security](#security) +5. [Documentation](#documentation) 1. [Authelia configuration](#authelia-configuration) - 1. [API documentation](#api-documentation) -5. [Contributing to Authelia](#contributing-to-authelia) -6. [License](#license) + 2. [API documentation](#api-documentation) +6. [Contributing to Authelia](#contributing-to-authelia) +7. [License](#license) --- @@ -197,6 +198,29 @@ Please see [config.template.yml] to see an example of configuration. ### Session management with Redis When your users authenticate against Authelia, sessions are stored in a Redis key/value store. You can specify your own Redis instance in [config.template.yml]. +## Security + +### Protection against cookie theft + +Authelia uses two mechanism to protect against cookie theft: +1. session attribute `httpOnly` set to true make client-side code unable to +read the cookie. +2. session attribute `secure` ensure the cookie will never be sent over an +unsecure HTTP connections. + +### Protection against multi-domain cookie attacks + +Since Authelia uses multi-domain cookies to perform single sign-on, an +attacker who poisonned a user's DNS cache can easily retrieve the user's +cookies by making the user send a request to one of the attacker's IPs. + +To mitigate this risk, it's advisable to only use HTTPS connections with valid +certificates and enforce it with HTTP Strict Transport Security ([HSTS]) so +that the attacker must also require the certificate to retrieve the cookies. + +Note that using [HSTS] has consequences. That's why you should read the blog +post nginx has written on [HSTS]. + ## Documentation ### Authelia configuration The configuration of the server is defined in the file @@ -246,4 +270,4 @@ Follow [contributing](CONTRIBUTORS.md) file. [auth_request]: http://nginx.org/en/docs/http/ngx_http_auth_request_module.html [Google Authenticator]: https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=en [config.template.yml]: https://github.com/clems4ever/authelia/blob/master/config.template.yml - +[HSTS]: https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/ From 056565a9689dfe6557f8a3bf8dace41b9b9f43b7 Mon Sep 17 00:00:00 2001 From: Clement Michaud Date: Sun, 15 Oct 2017 18:03:18 +0200 Subject: [PATCH 4/4] Add X-Frame-Options header to avoid ability to embed websites in iframes --- example/nginx/nginx.conf | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/example/nginx/nginx.conf b/example/nginx/nginx.conf index 5c2150253..0db8f9d52 100644 --- a/example/nginx/nginx.conf +++ b/example/nginx/nginx.conf @@ -31,6 +31,7 @@ http { ssl_certificate_key /etc/ssl/server.key; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header X-Frame-Options "SAMEORIGIN"; location / { proxy_set_header X-Original-URI $request_uri; @@ -61,6 +62,7 @@ http { ssl_certificate_key /etc/ssl/server.key; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header X-Frame-Options "SAMEORIGIN"; } server { @@ -74,6 +76,7 @@ http { ssl_certificate_key /etc/ssl/server.key; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header X-Frame-Options "SAMEORIGIN"; location /auth_verify { internal; @@ -130,6 +133,7 @@ http { ssl_certificate_key /etc/ssl/server.key; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header X-Frame-Options "SAMEORIGIN"; location /auth_verify { internal; @@ -169,6 +173,7 @@ http { ssl_certificate_key /etc/ssl/server.key; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header X-Frame-Options "SAMEORIGIN"; location /auth_verify { internal; @@ -208,6 +213,7 @@ http { ssl_certificate_key /etc/ssl/server.key; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header X-Frame-Options "SAMEORIGIN"; location /auth_verify { internal; @@ -247,6 +253,7 @@ http { ssl_certificate_key /etc/ssl/server.key; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header X-Frame-Options "SAMEORIGIN"; location /auth_verify { internal;