xref: /openbmc/bmcweb/include/security_headers.hpp (revision d78572018fc2022091ff8b8eb5a7fef2172ba3d6)
140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0
240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors
352cc112dSEd Tanous #pragma once
452cc112dSEd Tanous 
53ccb3adbSEd Tanous #include "http_response.hpp"
652cc112dSEd Tanous 
7*d7857201SEd Tanous #include <boost/beast/http/field.hpp>
8*d7857201SEd Tanous 
addSecurityHeaders(crow::Response & res)989cda63dSEd Tanous inline void addSecurityHeaders(crow::Response& res)
1052cc112dSEd Tanous {
1152cc112dSEd Tanous     using bf = boost::beast::http::field;
1252cc112dSEd Tanous 
131d9502bbSJoseph Reynolds     // Recommendations from https://owasp.org/www-project-secure-headers/
141d9502bbSJoseph Reynolds     // https://owasp.org/www-project-secure-headers/ci/headers_add.json
15d8139c68SEd Tanous     res.addHeader(bf::strict_transport_security, "max-age=31536000; "
16d8139c68SEd Tanous                                                  "includeSubdomains");
17d8139c68SEd Tanous 
18d8139c68SEd Tanous     res.addHeader(bf::pragma, "no-cache");
19d8139c68SEd Tanous 
20499b5b4dSEd Tanous     if (res.getHeaderValue(bf::cache_control).empty())
21499b5b4dSEd Tanous     {
22499b5b4dSEd Tanous         res.addHeader(bf::cache_control, "no-store, max-age=0");
23499b5b4dSEd Tanous     }
24d8139c68SEd Tanous     res.addHeader("X-Content-Type-Options", "nosniff");
25d8139c68SEd Tanous 
26c056aa7aSEd Tanous     std::string_view contentType = res.getHeaderValue("Content-Type");
27c056aa7aSEd Tanous     if (contentType.starts_with("text/html"))
28c056aa7aSEd Tanous     {
29c056aa7aSEd Tanous         res.addHeader(bf::x_frame_options, "DENY");
301d9502bbSJoseph Reynolds         res.addHeader("Referrer-Policy", "no-referrer");
31bd79bce8SPatrick Williams         res.addHeader(
32bd79bce8SPatrick Williams             "Permissions-Policy",
33bd79bce8SPatrick Williams             "accelerometer=(),"
341d9502bbSJoseph Reynolds             "ambient-light-sensor=(),"
351d9502bbSJoseph Reynolds             "autoplay=(),"
361d9502bbSJoseph Reynolds             "battery=(),"
371d9502bbSJoseph Reynolds             "camera=(),"
381d9502bbSJoseph Reynolds             "display-capture=(),"
39d8139c68SEd Tanous             "document-domain=(),"
401d9502bbSJoseph Reynolds             "encrypted-media=(),"
411d9502bbSJoseph Reynolds             "fullscreen=(),"
42d8139c68SEd Tanous             "gamepad=(),"
431d9502bbSJoseph Reynolds             "geolocation=(),"
441d9502bbSJoseph Reynolds             "gyroscope=(),"
45d8139c68SEd Tanous             "layout-animations=(self),"
46d8139c68SEd Tanous             "legacy-image-formats=(self),"
471d9502bbSJoseph Reynolds             "magnetometer=(),"
481d9502bbSJoseph Reynolds             "microphone=(),"
491d9502bbSJoseph Reynolds             "midi=(),"
50d8139c68SEd Tanous             "oversized-images=(self),"
511d9502bbSJoseph Reynolds             "payment=(),"
521d9502bbSJoseph Reynolds             "picture-in-picture=(),"
531d9502bbSJoseph Reynolds             "publickey-credentials-get=(),"
549bdc8b55SJoseph Reynolds             "speaker-selection=(),"
55d8139c68SEd Tanous             "sync-xhr=(self),"
56d8139c68SEd Tanous             "unoptimized-images=(self),"
57d8139c68SEd Tanous             "unsized-media=(self),"
58d8139c68SEd Tanous             "usb=(),"
59d8139c68SEd Tanous             "screen-wak-lock=(),"
601d9502bbSJoseph Reynolds             "web-share=(),"
61d8139c68SEd Tanous             "xr-spatial-tracking=()");
62d8139c68SEd Tanous         res.addHeader("X-Permitted-Cross-Domain-Policies", "none");
63d8139c68SEd Tanous         res.addHeader("Cross-Origin-Embedder-Policy", "require-corp");
64d8139c68SEd Tanous         res.addHeader("Cross-Origin-Opener-Policy", "same-origin");
65d8139c68SEd Tanous         res.addHeader("Cross-Origin-Resource-Policy", "same-origin");
66bd79bce8SPatrick Williams         res.addHeader("Content-Security-Policy",
67bd79bce8SPatrick Williams                       "default-src 'none'; "
6852cc112dSEd Tanous                       "img-src 'self' data:; "
6952cc112dSEd Tanous                       "font-src 'self'; "
7052cc112dSEd Tanous                       "style-src 'self'; "
7152cc112dSEd Tanous                       "script-src 'self'; "
7209e7afdcSBasheer Ahmed Muddebihal                       "connect-src 'self' wss:; "
7309e7afdcSBasheer Ahmed Muddebihal                       "form-action 'none'; "
7409e7afdcSBasheer Ahmed Muddebihal                       "frame-ancestors 'none'; "
7591ac2e57SJiaqing Zhao                       "object-src 'none'; "
7609e7afdcSBasheer Ahmed Muddebihal                       "base-uri 'none' ");
7752cc112dSEd Tanous         // The KVM currently needs to load images from base64 encoded
7852cc112dSEd Tanous         // strings. img-src 'self' data: is used to allow that.
7909e7afdcSBasheer Ahmed Muddebihal         // https://stackoverflow.com/questions/18447970/content-security-polic
8009e7afdcSBasheer Ahmed Muddebihal         // y-data-not-working-for-base64-images-in-chrome-28
810260d9d6SEd Tanous     }
82c056aa7aSEd Tanous }
83