wsd: support providing CSP header in the config

Signed-off-by: Ashod Nakashian <ashod.nakashian@collabora.co.uk>
(cherry picked from commit 25fe0b2dfb)

Change-Id: I3e1f3085846ab31326a0a788e7332b5332c10c94
pull/6646/head
Ashod Nakashian 2023-06-09 07:42:46 -04:00 committed by Ashod Nakashian
parent df898ae3a3
commit 7a634d0790
3 changed files with 22 additions and 8 deletions

View File

@ -160,7 +160,8 @@
<host desc="The IPv4 private 10.0.0.0/8 subnet (Podman).">10\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}</host>
<host desc="Ditto, but as IPv4-mapped IPv6 addresses">::ffff:10\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}</host>
</post_allow>
<frame_ancestors desc="Specify who is allowed to embed the Collabora Online iframe (coolwsd and WOPI host are always allowed). Separate multiple hosts by space."></frame_ancestors>
<content_security_policy desc="Customize the CSP header by specifying one or more policy-directive, separated by semicolons. See w3.org/TR/CSP2"></content_security_policy>
<frame_ancestors desc="OBSOLETE: Use content_security_policy. Specify who is allowed to embed the Collabora Online iframe (coolwsd and WOPI host are always allowed). Separate multiple hosts by space."></frame_ancestors>
<connection_timeout_secs desc="Specifies the connection, send, recv timeout in seconds for connections initiated by coolwsd (such as WOPI connections)." type="int" default="30"></connection_timeout_secs>
<!-- this setting radically changes how online works, it should not be used in a production environment -->

View File

@ -1980,6 +1980,8 @@ void COOLWSD::innerInitialize(Application& self)
{ "net.proto", "all" },
{ "net.service_root", "" },
{ "net.proxy_prefix", "false" },
{ "net.content_security_policy", "" },
{ "net.frame_ancestors", "" },
{ "num_prespawn_children", "1" },
{ "per_document.always_save_on_exit", "false" },
{ "per_document.autosave_duration_secs", "300" },
@ -2081,7 +2083,7 @@ void COOLWSD::innerInitialize(Application& self)
#if !MOBILEAPP
{ "help_url", HELP_URL },
#endif
{ "product_name", APP_NAME}
{ "product_name", APP_NAME }
};
// Set default values, in case they are missing from the config file.

View File

@ -1062,6 +1062,8 @@ void FileServerRequestHandler::preprocessFile(const HTTPRequest& request,
const std::string mimeType = "text/html";
// Document signing: if endpoint URL is configured, whitelist that for
// iframe purposes.
ContentSecurityPolicy csp;
csp.appendDirective("default-src", "'none'");
csp.appendDirective("frame-src", "'self'");
@ -1088,11 +1090,20 @@ void FileServerRequestHandler::preprocessFile(const HTTPRequest& request,
csp.appendDirective("img-src", "data:"); // Equivalent to unsafe-inline!
csp.appendDirective("img-src", "https://www.collaboraoffice.com/");
std::ostringstream cspOss;
cspOss << "Content-Security-Policy: ";
// Frame ancestors: Allow coolwsd host, wopi host and anything configured.
std::string configFrameAncestor = config.getString("net.frame_ancestors", "");
const std::string configFrameAncestor = config.getString("net.frame_ancestors", "");
if (!configFrameAncestor.empty())
{
static bool warned = false;
if (!warned)
{
warned = true;
LOG_WRN("The config entry net.frame_ancestors is obsolete and will be removed in the "
"future. Please add 'frame-ancestors "
<< configFrameAncestor << "' in the net.content_security_policy config");
}
}
std::string frameAncestors = configFrameAncestor;
Poco::URI uriHost(cnxDetails.getWebSocketUrl());
if (uriHost.getHost() != configFrameAncestor)
@ -1130,7 +1141,7 @@ void FileServerRequestHandler::preprocessFile(const HTTPRequest& request,
LOG_TRC("Denied all frame ancestors");
}
cspOss << csp.generate() << "\r\n";
csp.merge(config.getString("net.content_security_policy", ""));
std::ostringstream oss;
oss << "HTTP/1.1 200 OK\r\n"
@ -1146,7 +1157,7 @@ void FileServerRequestHandler::preprocessFile(const HTTPRequest& request,
"Referrer-Policy: no-referrer\r\n";
// Append CSP to response headers too
oss << cspOss.str();
oss << "Content-Security-Policy: " << csp.generate() << "\r\n";
// Setup HTTP Public key pinning
if ((COOLWSD::isSSLEnabled() || COOLWSD::isSSLTermination()) && config.getBool("ssl.hpkp[@enable]", false))