This is an automated email from the ASF dual-hosted git repository. asherman pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/impala.git
commit 59667b751b1aaac808c83a276e458e55ba116512 Author: Michael Smith <[email protected]> AuthorDate: Wed Mar 29 11:21:15 2023 -0700 IMPALA-12031: Add security-related HTTP headers Adds security-related headers - X-Content-Type-Options: nosniff - Cache-Control: no-store - Strict-Transport-Security: max-age=31536000; includeSubDomains These are primarily no-ops as Impala never serves HTTP and HTTPS at the same time, and does not provide any way to upload files. Strict-Transport-Security is only added when serving HTTPS. Testing: - manually interacted with web UI over HTTP and HTTPS, verified headers in responses - ran webserver-test Change-Id: I58e12961e7faa31f42bc2e6bd4de23b56e3dfd5f Reviewed-on: http://gerrit.cloudera.org:8080/19661 Reviewed-by: Impala Public Jenkins <[email protected]> Tested-by: Impala Public Jenkins <[email protected]> --- be/src/util/webserver-test.cc | 25 +++++++++++++++++++++++++ be/src/util/webserver.cc | 7 +++++++ 2 files changed, 32 insertions(+) diff --git a/be/src/util/webserver-test.cc b/be/src/util/webserver-test.cc index 26ee1ee28..29256cbea 100644 --- a/be/src/util/webserver-test.cc +++ b/be/src/util/webserver-test.cc @@ -15,6 +15,8 @@ // specific language governing permissions and limitations // under the License. +#include <array> +#include <memory> #include <string> #include <boost/asio.hpp> #include <boost/bind.hpp> @@ -136,6 +138,19 @@ Status HttpGet(const string& host, const int32_t& port, const string& url_path, return HttpRequest{url_path, host, port}.Do(out, expected_code, method); } +string exec(const char* cmd) { + std::array<char, 1024> buffer; + string result; + unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose); + if (!pipe) { + throw std::runtime_error(Substitute("popen() failed with $0", errno)); + } + while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { + result += buffer.data(); + } + return result; +} + TEST(Webserver, SmokeTest) { MetricGroup metrics("webserver-test"); Webserver webserver("", FLAGS_webserver_port, &metrics); @@ -144,6 +159,9 @@ TEST(Webserver, SmokeTest) { stringstream contents; ASSERT_OK(HttpGet("localhost", FLAGS_webserver_port, "/", &contents)); + ASSERT_TRUE(contents.str().find("X-Content-Type-Options: nosniff") != string::npos); + ASSERT_TRUE(contents.str().find("Cache-Control: no-store") != string::npos); + ASSERT_TRUE(contents.str().find("Strict-Transport-Security: ") == string::npos); } void PostOnlyCallback(bool* success, const Webserver::WebRequest& req, @@ -285,6 +303,13 @@ TEST(Webserver, SslTest) { MetricGroup metrics("webserver-test"); Webserver webserver("", FLAGS_webserver_port, &metrics); ASSERT_OK(webserver.Start()); + AddDefaultUrlCallbacks(&webserver); + + string cmd = Substitute("curl -v -f -s --cacert $0 'https://localhost:$1' 2>&1", + FLAGS_webserver_certificate_file, FLAGS_webserver_port); + string response = exec(cmd.c_str()); + ASSERT_TRUE(response.find( + "Strict-Transport-Security: max-age=31536000; includeSubDomains") != string::npos); } TEST(Webserver, SslBadCertTest) { diff --git a/be/src/util/webserver.cc b/be/src/util/webserver.cc index 9d2716591..d5a754911 100644 --- a/be/src/util/webserver.cc +++ b/be/src/util/webserver.cc @@ -239,9 +239,16 @@ void SendResponse(struct sq_connection* connection, const string& response_code_ oss << h << CRLF; } oss << "X-Frame-Options: " << FLAGS_webserver_x_frame_options << CRLF; + oss << "X-Content-Type-Options: nosniff" << CRLF; + oss << "Cache-Control: no-store" << CRLF; if (!FLAGS_disable_content_security_policy_header) { oss << "Content-Security-Policy: " << CSP_HEADER << CRLF; } + + struct sq_request_info* request_info = sq_get_request_info(connection); + if (request_info->is_ssl) { + oss << "Strict-Transport-Security: max-age=31536000; includeSubDomains" << CRLF; + } oss << "Content-Type: " << content_type << CRLF; oss << "Content-Length: " << content.size() << CRLF; oss << CRLF;
