浏览代码

Merge branch 'master' into ssl-modern

Nicolas Duchon 7 年之前
父节点
当前提交
ea80027525

+ 1 - 1
Dockerfile

@@ -1,5 +1,5 @@
 FROM nginx:1.13
-MAINTAINER Jason Wilder mail@jasonwilder.com
+LABEL maintainer="Jason Wilder mail@jasonwilder.com"
 
 # Install wget and install/updates certificates
 RUN apt-get update \

+ 1 - 1
Dockerfile.alpine

@@ -1,5 +1,5 @@
 FROM nginx:1.13-alpine
-MAINTAINER Jason Wilder mail@jasonwilder.com
+LABEL maintainer="Jason Wilder mail@jasonwilder.com"
 
 # Install wget and install/updates certificates
 RUN apk add --no-cache --virtual .run-deps \

+ 7 - 0
README.md

@@ -272,6 +272,13 @@ site after changing this setting, your browser has probably cached the HSTS poli
 redirecting you back to HTTPS.  You will need to clear your browser's HSTS cache or use an incognito 
 window / different browser.
 
+By default, [HTTP Strict Transport Security (HSTS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security) 
+is enabled with `max-age=31536000` for HTTPS sites.  You can disable HSTS with the environment variable 
+`HSTS=off` or use a custom HSTS configuration like `HSTS=max-age=31536000; includeSubDomains; preload`.  
+*WARNING*: HSTS will force your users to visit the HTTPS version of your site for the `max-age` time - 
+even if they type in `http://` manually.  The only way to get to an HTTP site after receiving an HSTS 
+response is to clear your browser's HSTS cache.
+
 ### Basic Authentication Support
 
 In order to be able to secure your virtual host, you have to create a file named as its equivalent VIRTUAL_HOST variable on directory

+ 5 - 2
nginx.tmpl

@@ -161,6 +161,9 @@ upstream {{ $upstream_name }} {
 {{/* Get the MODERN_SSL defined by containers w/ the same vhost, falling back to "false" */}}
 {{ $modern_ssl := or (first (groupByKeys $containers "Env.MODERN_SSL")) "false" }}
 
+{{/* Get the HSTS defined by containers w/ the same vhost, falling back to "max-age=31536000" */}}
+{{ $hsts := or (first (groupByKeys $containers "Env.HSTS")) "max-age=31536000" }}
+
 {{/* Get the VIRTUAL_ROOT By containers w/ use fastcgi root */}}
 {{ $vhost_root := or (first (groupByKeys $containers "Env.VIRTUAL_ROOT")) "/var/www/public" }}
 
@@ -233,8 +236,8 @@ server {
 	ssl_trusted_certificate {{ printf "/etc/nginx/certs/%s.chain.crt" $cert }};
 	{{ end }}
 
-	{{ if (ne $https_method "noredirect") }}
-	add_header Strict-Transport-Security "max-age=31536000";
+	{{ if (and (ne $https_method "noredirect") (ne $hsts "off")) }}
+	add_header Strict-Transport-Security "{{ trim $hsts }}";
 	{{ end }}
 
 	{{ if (exists (printf "/etc/nginx/vhost.d/%s" $host)) }}

+ 1 - 1
test/test_ssl/test_dhparam.py

@@ -89,5 +89,5 @@ def test_web5_dhparam_is_used(docker_compose):
 
     host = "%s:443" % sut_container.attrs["NetworkSettings"]["IPAddress"]
     r = subprocess.check_output(
-        "echo '' | openssl s_client -verify 0 -connect %s -cipher 'EDH' | grep 'Server Temp Key'" % host, shell=True)
+        "echo '' | openssl s_client -connect %s -cipher 'EDH' | grep 'Server Temp Key'" % host, shell=True)
     assert "Server Temp Key: DH, 2048 bits\n" == r

+ 19 - 0
test/test_ssl/test_hsts.py

@@ -0,0 +1,19 @@
+import pytest
+
+
+def test_web1_HSTS_default(docker_compose, nginxproxy):
+    r = nginxproxy.get("https://web1.nginx-proxy.tld/port", allow_redirects=False)
+    assert "answer from port 81\n" in r.text
+    assert "Strict-Transport-Security" in r.headers
+    assert "max-age=31536000" == r.headers["Strict-Transport-Security"]
+
+def test_web2_HSTS_off(docker_compose, nginxproxy):
+    r = nginxproxy.get("https://web2.nginx-proxy.tld/port", allow_redirects=False)
+    assert "answer from port 81\n" in r.text
+    assert "Strict-Transport-Security" not in r.headers
+
+def test_web3_HSTS_custom(docker_compose, nginxproxy):
+    r = nginxproxy.get("https://web3.nginx-proxy.tld/port", allow_redirects=False)
+    assert "answer from port 81\n" in r.text
+    assert "Strict-Transport-Security" in r.headers
+    assert "max-age=86400; includeSubDomains; preload" == r.headers["Strict-Transport-Security"]

+ 32 - 0
test/test_ssl/test_hsts.yml

@@ -0,0 +1,32 @@
+web1:
+  image: web
+  expose:
+    - "81"
+  environment:
+    WEB_PORTS: "81"
+    VIRTUAL_HOST: "web1.nginx-proxy.tld"
+
+web2:
+  image: web
+  expose:
+    - "81"
+  environment:
+    WEB_PORTS: "81"
+    VIRTUAL_HOST: "web2.nginx-proxy.tld"
+    HSTS: "off"
+
+web3:
+  image: web
+  expose:
+    - "81"
+  environment:
+    WEB_PORTS: "81"
+    VIRTUAL_HOST: "web3.nginx-proxy.tld"
+    HSTS: "max-age=86400; includeSubDomains; preload"
+
+sut:
+  image: jwilder/nginx-proxy:test
+  volumes:
+    - /var/run/docker.sock:/tmp/docker.sock:ro
+    - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
+    - ./certs:/etc/nginx/certs:ro

+ 2 - 1
test/test_ssl/wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py

@@ -1,5 +1,6 @@
 import pytest
 from backports.ssl_match_hostname import CertificateError
+from requests.exceptions import SSLError
 
 
 @pytest.mark.parametrize("subdomain,should_redirect_to_https", [
@@ -23,7 +24,7 @@ def test_https_get_served(docker_compose, nginxproxy, subdomain):
 
 
 def test_web3_https_is_500_and_SSL_validation_fails(docker_compose, nginxproxy):
-    with pytest.raises(CertificateError) as excinfo:
+    with pytest.raises( (CertificateError, SSLError) ) as excinfo:
         nginxproxy.get("https://3.web.nginx-proxy.tld/port")
     assert """hostname '3.web.nginx-proxy.tld' doesn't match 'nginx-proxy.tld'""" in str(excinfo.value)