From 10380e43f3a7ba37ac3505de0046f27441037041 Mon Sep 17 00:00:00 2001 From: chang-ning Date: Wed, 12 Sep 2018 22:16:22 +0800 Subject: [PATCH] add security headers --- app.py | 6 ++++++ app_test.py | 13 +++++++++++++ docs/conf.py | 1 - requirements.txt | 2 ++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/app.py b/app.py index 204ae671..0bdf7333 100644 --- a/app.py +++ b/app.py @@ -4,6 +4,8 @@ from flask import Flask, abort, send_from_directory from flask_sslify import SSLify +from flask_seasurf import SeaSurf +from flask_talisman import Talisman DIR = os.path.dirname(os.path.realpath(__file__)) ROOT = os.path.join(DIR, "docs", "_build", "html") @@ -19,7 +21,11 @@ def find_key(token): return os.environ.get("ACME_KEY_{}".format(n)) +csp = {"default-src": ["*", "'unsafe-inline'", "'unsafe-eval'"]} app = Flask(__name__) +app.config["SECRET_KEY"] = os.urandom(16) +csrf = SeaSurf(app) +talisman = Talisman(app, force_https=False, content_security_policy=csp) if "DYNO" in os.environ: sslify = SSLify(app, skips=[".well-known"]) diff --git a/app_test.py b/app_test.py index 53d3f0ee..30054f12 100644 --- a/app_test.py +++ b/app_test.py @@ -34,10 +34,20 @@ def create_app(self): app.config["LIVESERVER_PORT"] = 0 return app + def check_security_headers(self, resp): + """Check security headers.""" + headers = resp.headers + self.assertTrue("X-Content-Security-Policy" in headers) + self.assertTrue("X-XSS-Protection" in headers) + self.assertTrue("X-Content-Type-Options" in headers) + self.assertTrue("Content-Security-Policy" in headers) + self.assertEqual(headers["X-Frame-Options"], "SAMEORIGIN") + def test_index_redirection_req(self): """Test that send a request for the index page.""" url = self.get_server_url() resp = requests.get(url) + self.check_security_headers(resp) self.assertEqual(resp.status_code, 200) def test_static_proxy_req(self): @@ -47,6 +57,7 @@ def test_static_proxy_req(self): for h in htmls: u = url + "/notes/" + h resp = requests.get(u) + self.check_security_headers(resp) self.assertEqual(resp.status_code, 200) def test_acme_req(self): @@ -54,10 +65,12 @@ def test_acme_req(self): url = self.get_server_url() u = url + "/.well-known/acme-challenge/token" resp = requests.get(u) + self.check_security_headers(resp) self.assertEqual(resp.status_code, 200) u = url + "/.well-known/acme-challenge/foo" resp = requests.get(u) + self.check_security_headers(resp) self.assertEqual(resp.status_code, 404) def test_find_key(self): diff --git a/docs/conf.py b/docs/conf.py index cdf53db0..5a618966 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -31,7 +31,6 @@ extensions = [ 'sphinx.ext.todo', 'sphinx.ext.coverage', - 'sphinx.ext.mathjax', 'sphinx.ext.viewcode', ] diff --git a/requirements.txt b/requirements.txt index 96a65ed4..375547af 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,6 +6,8 @@ docutils==0.14 Flask==1.0.2 Flask-SSLify==0.1.5 Flask-Testing==0.7.1 +Flask-SeaSurf==0.2.2 +flask-talisman==0.5.1 gunicorn==19.9.0 pycodestyle==2.4.0 pydocstyle==2.1.1