diff options
| -rw-r--r-- | custom/servers/apache.conf | 60 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | custom/servers/lighttpd.conf | 46 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | custom/servers/nginx.conf | 56 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3 files changed, 132 insertions, 30 deletions
diff --git a/custom/servers/apache.conf b/custom/servers/apache.conf index 4345a9e..3c035f7 100644 --- a/custom/servers/apache.conf +++ b/custom/servers/apache.conf @@ -175,8 +175,9 @@ AddType text/plain .txt # The vhost that serves cgit. To run without TLS for now, change this opening -# line to port 80, delete the SSL lines, and delete the vhost above so there -# is only one. Everything else stays as it is. +# line to port 80, delete the SSL lines, delete the Strict-Transport-Security +# line, and delete the vhost above so there is only one. Everything else stays +# as it is. <VirtualHost *:443> ServerName git.example.org @@ -201,16 +202,53 @@ AddType text/plain .txt # it stops after 4096 bytes. Nothing else here accepts an upload. LimitRequestBody 65536 - # Security headers are set here, not in cgit, so they also cover the static - # assets Apache serves. script-src stays self because cgit loads only its - # own cgit.js, and style-src allows inline for the diffstat bars. If you - # enable the gravatar or libravatar avatar filter, add its host to img-src, - # for example https://www.gravatar.com. - Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; object-src 'none'; base-uri 'none'; frame-ancestors 'self'" - Header always set X-Content-Type-Options "nosniff" + # Site-wide security headers are set here so they also cover the static + # assets Apache serves. cgit itself sends only the headers the proxy + # cannot supply. Those are Status, Content-Type, Content-Length and + # Content-Disposition on downloads, a no-store Cache-Control on + # unauthenticated responses, the auth filter's Set-Cookie, and on raw + # repository bytes a nosniff of its own next to the stricter policy + # "default-src 'none'". Everything else, this policy included, is the + # proxy's job. + # + # The word setifempty is load bearing on the two headers cgit can also + # emit. "Header always set" replaces a same-named header even when the + # CGI sent it, which was verified against Apache 2.4.67 and would swap + # the strict policy on raw repository content for this looser site one. + # setifempty yields to whatever cgit sent and still covers every response + # without one, the HTML pages, the static assets, and with always also + # Apache's own error pages. Referrer-Policy stays a plain set because + # cgit never emits it, so there is nothing to overwrite. + # + # script-src stays self because cgit loads only its own cgit.js, and + # style-src allows inline for the diffstat bars. form-action self covers + # the login form, the only form cgit renders. If you enable the gravatar + # or libravatar avatar filter, add its host to img-src, for example + # https://www.gravatar.com. + Header always setifempty Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; object-src 'none'; base-uri 'none'; frame-ancestors 'self'; form-action 'self'" + Header always setifempty X-Content-Type-Options "nosniff" Header always set Referrer-Policy "no-referrer" - # Enable only once you serve HTTPS exclusively, since it is hard to undo. - #Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains" + + # The browser features a git viewer never asks for, camera and location + # among them, are refused outright for everything served here, repository + # files included. + Header always set Permissions-Policy "accelerometer=(), autoplay=(), camera=(), display-capture=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), usb=()" + + # Cross-origin isolation. The opener policy cuts any window.opener link + # between cgit and pages that open it, and the resource policy stops + # other origins from embedding what cgit serves, a hotlinked raw file for + # example. git clients are not browsers and ignore both, so clone and + # snapshot downloads keep working. The stricter + # Cross-Origin-Embedder-Policy is deliberately absent because it would + # break the avatar filters mentioned above. + Header always set Cross-Origin-Opener-Policy "same-origin" + Header always set Cross-Origin-Resource-Policy "same-origin" + + # Two years of forced HTTPS. This config already redirects every plain + # request to TLS, so browsers may as well stop asking. Delete this line + # if you convert the vhost to plain HTTP, and know it is hard to undo + # once browsers have seen it. + Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains" # These five files are the only things served off disk. Each Alias maps # one URL to one file. Because they come before the ScriptAlias below, a diff --git a/custom/servers/lighttpd.conf b/custom/servers/lighttpd.conf index 6ae87e0..dcfb43d 100644 --- a/custom/servers/lighttpd.conf +++ b/custom/servers/lighttpd.conf @@ -73,17 +73,47 @@ $HTTP["host"] == "git.example.org" { # the same path used here, but setting it makes the location explicit. setenv.add-environment = ( "CGIT_CONFIG" => "/etc/cgitrc" ) - # Security headers are set here, not in cgit, so they also cover the - # static assets lighttpd serves. script-src stays self because cgit loads - # only its own cgit.js, and style-src allows inline for the diffstat bars. - # If you enable the gravatar or libravatar avatar filter, add its host to - # img-src. + # Site-wide security headers are set here so they also cover the static + # assets lighttpd serves. cgit itself sends only the headers the server + # cannot supply. Those are Status, Content-Type, Content-Length and + # Content-Disposition on downloads, a no-store Cache-Control on + # unauthenticated responses, the auth filter's Set-Cookie, and on raw + # repository bytes a nosniff of its own next to the stricter policy + # "default-src 'none'". Everything else, this policy included, is the + # server's job. + # + # The add in add-response-header is load bearing. It appends a second + # copy next to what cgit emitted, so a raw page carries both policies and + # the browser enforces the stricter one, while the doubled nosniff line + # is harmless. The set-response-header directive would instead replace + # what cgit sent, swapping the strict policy on raw repository content + # for this looser site one. Never switch add to set. + # + # script-src stays self because cgit loads only its own cgit.js, and + # style-src allows inline for the diffstat bars. form-action self covers + # the login form, the only form cgit renders. If you enable the gravatar + # or libravatar avatar filter, add its host to img-src. + # + # Permissions-Policy refuses the browser features a git viewer never asks + # for, camera and location among them, for everything served here, + # repository files included. The opener policy cuts any window.opener + # link between cgit and pages that open it, and the resource policy stops + # other origins from embedding what cgit serves, a hotlinked raw file for + # example. git clients are not browsers and ignore both, so clone and + # snapshot downloads keep working. The stricter + # Cross-Origin-Embedder-Policy is deliberately absent because it would + # break the avatar filters mentioned above. setenv.add-response-header = ( - "Content-Security-Policy" => "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; object-src 'none'; base-uri 'none'; frame-ancestors 'self'", + "Content-Security-Policy" => "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; object-src 'none'; base-uri 'none'; frame-ancestors 'self'; form-action 'self'", "X-Content-Type-Options" => "nosniff", - "Referrer-Policy" => "no-referrer" + "Referrer-Policy" => "no-referrer", + "Permissions-Policy" => "accelerometer=(), autoplay=(), camera=(), display-capture=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), usb=()", + "Cross-Origin-Opener-Policy" => "same-origin", + "Cross-Origin-Resource-Policy" => "same-origin" ) - # Enable only once you serve HTTPS exclusively, since it is hard to undo. + # Two years of forced HTTPS. Enable this together with the TLS socket at + # the end of this file and only once you serve HTTPS exclusively, since + # it is hard to undo once browsers have seen it. #setenv.add-response-header += ( "Strict-Transport-Security" => "max-age=63072000; includeSubDomains" ) # Register the cgit binary as a CGI program. The key cgit.cgi matches the diff --git a/custom/servers/nginx.conf b/custom/servers/nginx.conf index 12d6888..f26598c 100644 --- a/custom/servers/nginx.conf +++ b/custom/servers/nginx.conf @@ -101,7 +101,8 @@ http { # The site itself, written for TLS on 443. For a quick plain-HTTP test, # change the two listen lines to port 80, delete the redirect block above, - # and delete the http2 and ssl lines below. Everything else stays as it is. + # and delete the http2, ssl and Strict-Transport-Security lines below. + # Everything else stays as it is. server { listen 443 ssl; listen [::]:443 ssl; @@ -123,18 +124,51 @@ http { ssl_session_timeout 1d; ssl_session_tickets off; - # Security headers sit here, not in cgit, because they must also cover - # the static assets nginx serves directly. cgit loads only its own - # /cgit.js and uses inline style on the diffstat bars, so script-src - # stays self while style-src allows inline. always applies them to - # error responses too. If you enable the gravatar or libravatar avatar - # filter, add its host to img-src, for example https://www.gravatar.com - # or https://seccdn.libravatar.org. - add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; object-src 'none'; base-uri 'none'; frame-ancestors 'self'" always; + # Site-wide security headers sit here because they must also cover the + # static assets nginx serves directly. cgit itself sends only the + # headers the proxy cannot supply. Those are Status, Content-Type, + # Content-Length and Content-Disposition on downloads, a no-store + # Cache-Control on unauthenticated responses, the auth filter's + # Set-Cookie, and on raw repository bytes a nosniff of its own next to + # the stricter policy "default-src 'none'". Everything else, this + # policy included, is the proxy's job. + # + # add_header appends and never replaces what cgit sent, so a raw page + # carries both policies and the browser enforces the stricter one, + # while the doubled nosniff line is harmless. Keep it that way. Any + # construct that rewrites response headers here could strip the + # protection cgit puts on raw repository content. + # + # cgit loads only its own /cgit.js and uses inline style on the + # diffstat bars, so script-src stays self while style-src allows + # inline. form-action self covers the login form, the only form cgit + # renders. always applies them to error responses too. If you enable + # the gravatar or libravatar avatar filter, add its host to img-src, + # for example https://www.gravatar.com or https://seccdn.libravatar.org. + add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; object-src 'none'; base-uri 'none'; frame-ancestors 'self'; form-action 'self'" always; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "no-referrer" always; - # Enable only once you serve HTTPS exclusively, since it is hard to undo. - #add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always; + + # The browser features a git viewer never asks for, camera and + # location among them, are refused outright for everything served + # here, repository files included. + add_header Permissions-Policy "accelerometer=(), autoplay=(), camera=(), display-capture=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), usb=()" always; + + # Cross-origin isolation. The opener policy cuts any window.opener + # link between cgit and pages that open it, and the resource policy + # stops other origins from embedding what cgit serves, a hotlinked + # raw file for example. git clients are not browsers and ignore both, + # so clone and snapshot downloads keep working. The stricter + # Cross-Origin-Embedder-Policy is deliberately absent because it + # would break the avatar filters mentioned above. + add_header Cross-Origin-Opener-Policy "same-origin" always; + add_header Cross-Origin-Resource-Policy "same-origin" always; + + # Two years of forced HTTPS. This config already redirects every + # plain request to TLS, so browsers may as well stop asking. Delete + # this line if you convert the vhost to plain HTTP, and know it is + # hard to undo once browsers have seen it. + add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always; # The document root is the directory that holds the static assets. cgit # emits absolute links to /cgit.css and /cgit.png by default, so those |
