diff options
author | Tor Brede Vekterli <vekterli@verizonmedia.com> | 2019-08-13 14:23:45 +0000 |
---|---|---|
committer | Tor Brede Vekterli <vekterli@verizonmedia.com> | 2019-08-13 15:27:57 +0000 |
commit | d0e2b5082708cdf5044509dc242cfadc6ee68461 (patch) | |
tree | 0744565a97de7b7ec9746e1caa285b08f77de320 /vespalib | |
parent | e15d87688f4da812e93500598fa653164b47b9bd (diff) |
Set basic HTTP security headers on status pages served from backend
We should already escape everything printed on these pages, but as part
of a defense in depth strategy we use a restrictive set of HTTP security
headers to minimize the impact in the case of a regression or bug.
Diffstat (limited to 'vespalib')
-rw-r--r-- | vespalib/src/tests/portal/portal_test.cpp | 6 | ||||
-rw-r--r-- | vespalib/src/vespa/vespalib/portal/http_connection.cpp | 21 |
2 files changed, 27 insertions, 0 deletions
diff --git a/vespalib/src/tests/portal/portal_test.cpp b/vespalib/src/tests/portal/portal_test.cpp index 1baebc69e97..e54700306fe 100644 --- a/vespalib/src/tests/portal/portal_test.cpp +++ b/vespalib/src/tests/portal/portal_test.cpp @@ -48,6 +48,12 @@ vespalib::string make_expected_response(const vespalib::string &content_type, co "Connection: close\r\n" "Content-Type: %s\r\n" "Content-Length: %zu\r\n" + "X-XSS-Protection: 1; mode=block\r\n" + "X-Frame-Options: DENY\r\n" + "Content-Security-Policy: default-src 'none'\r\n" + "X-Content-Type-Options: nosniff\r\n" + "Cache-Control: no-store\r\n" + "Pragma: no-cache\r\n" "\r\n" "%s", content_type.c_str(), content.size(), content.c_str()); } diff --git a/vespalib/src/vespa/vespalib/portal/http_connection.cpp b/vespalib/src/vespa/vespalib/portal/http_connection.cpp index 97a5f6082c9..aa2c0ec4cdd 100644 --- a/vespalib/src/vespa/vespalib/portal/http_connection.cpp +++ b/vespalib/src/vespa/vespalib/portal/http_connection.cpp @@ -90,6 +90,26 @@ WriteRes half_close(CryptoSocket &socket) { } } +/** + * Emit a basic set of HTTP security headers meant to minimize any impact + * in the case of unsanitized/unescaped data making its way to an internal + * status page. + */ +void emit_http_security_headers(OutputWriter &dst) { + // Reject detected cross-site scripting attacks + dst.printf("X-XSS-Protection: 1; mode=block\r\n"); + // Do not allow embedding via iframe (clickjacking prevention) + dst.printf("X-Frame-Options: DENY\r\n"); + // Do not allow _anything_ to be externally loaded, nor inline scripts + // etc to be executed. + dst.printf("Content-Security-Policy: default-src 'none'\r\n"); + // No heuristic auto-inference of content-type based on payload. + dst.printf("X-Content-Type-Options: nosniff\r\n"); + // Don't store any potentially sensitive data in any caches. + dst.printf("Cache-Control: no-store\r\n"); + dst.printf("Pragma: no-cache\r\n"); +} + } // namespace vespalib::portal::<unnamed> void @@ -223,6 +243,7 @@ HttpConnection::respond_with_content(const vespalib::string &content_type, dst.printf("Connection: close\r\n"); dst.printf("Content-Type: %s\r\n", content_type.c_str()); dst.printf("Content-Length: %zu\r\n", content.size()); + emit_http_security_headers(dst); dst.printf("\r\n"); dst.write(content.data(), content.size()); } |