diff --git a/docs/example.nginx.conf b/docs/example.nginx.conf index 13fd7789f..be56e10cd 100644 --- a/docs/example.nginx.conf +++ b/docs/example.nginx.conf @@ -19,6 +19,16 @@ server { set $main_domain "your-main-domain.com"; set $sandbox_domain "your-sandbox-domain.com"; + # By default CryptPad allows remote domains to embed CryptPad documents in iframes. + # This behaviour can be blocked by changing $allowed_origins from "*" to the + # sandbox domain, which must be permitted to load content from the main domain + # in order for CryptPad to work as expected. + # + # An example is given below which can be uncommented if you want to block + # remote sites from including content from your server + set $allowed_origins "*"; + # set $allowed_origins "https://${sandbox_domain}"; + # CryptPad's dynamic content (websocket traffic and encrypted blobs) # can be served over separate domains. Using dedicated domains (or subdomains) # for these purposes allows you to move them to a separate machine at a later date @@ -58,7 +68,7 @@ server { add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-XSS-Protection "1; mode=block"; add_header X-Content-Type-Options nosniff; - add_header Access-Control-Allow-Origin "*"; + add_header Access-Control-Allow-Origin "${allowed_origins}"; # add_header X-Frame-Options "SAMEORIGIN"; # Opt out of Google's FLoC Network @@ -115,6 +125,9 @@ server { # script-src specifies valid sources for javascript, including inline handlers set $scriptSrc "'self' resource: https://${main_domain}"; + # XXX frame-ancestors defines where your cryptpad instance can be embedded... + set $frameAncestors "https://${main_domain} $https://${sandbox_domain}"; + set $unsafe 0; # the following assets are loaded via the sandbox domain # they unfortunately still require exceptions to the sandboxing to work correctly. @@ -135,7 +148,7 @@ server { } # Finally, set all the rules you composed above. - add_header Content-Security-Policy "default-src 'none'; child-src $childSrc; worker-src $workerSrc; media-src $mediaSrc; style-src $styleSrc; script-src $scriptSrc; connect-src $connectSrc; font-src $fontSrc; img-src $imgSrc; frame-src $frameSrc;"; + add_header Content-Security-Policy "default-src 'none'; child-src $childSrc; worker-src $workerSrc; media-src $mediaSrc; style-src $styleSrc; script-src $scriptSrc; connect-src $connectSrc; font-src $fontSrc; img-src $imgSrc; frame-src $frameSrc; frame-ancestors $frameAncestors"; # The nodejs process can handle all traffic whether accessed over websocket or as static assets # We prefer to serve static content from nginx directly and to leave the API server to handle @@ -183,7 +196,7 @@ server { # encrypted blobs are immutable and are thus cached for a year location ^~ /blob/ { if ($request_method = 'OPTIONS') { - add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Origin' "${allowed_origins}"; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range'; add_header 'Access-Control-Max-Age' 1728000; @@ -192,7 +205,7 @@ server { return 204; } add_header Cache-Control max-age=31536000; - add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Origin' "${allowed_origins}"; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,Content-Length'; add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,Content-Length';