Merge pull request #152 from clems4ever/cookie-theft

Prevention agains cookie theft
pull/160/head
Clément Michaud 2017-10-16 21:11:58 +02:00 committed by GitHub
commit 39b3898908
8 changed files with 68 additions and 13 deletions

View File

@ -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/

View File

@ -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:

View File

@ -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:

View File

@ -30,11 +30,14 @@ http {
ssl_certificate /etc/ssl/server.crt;
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;
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/;
@ -57,6 +60,9 @@ 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;
add_header X-Frame-Options "SAMEORIGIN";
}
server {
@ -69,10 +75,14 @@ http {
ssl_certificate /etc/ssl/server.crt;
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;
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 "";
@ -122,10 +132,14 @@ http {
ssl_certificate /etc/ssl/server.crt;
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;
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 "";
@ -158,10 +172,14 @@ http {
ssl_certificate /etc/ssl/server.crt;
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;
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 "";
@ -194,10 +212,14 @@ http {
ssl_certificate /etc/ssl/server.crt;
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;
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 "";
@ -230,10 +252,14 @@ http {
ssl_certificate /etc/ssl/server.crt;
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;
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 "";

View File

@ -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");

View File

@ -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);

View File

@ -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
},

View File

@ -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"
},