diff options
context:
space:
mode:
authorBryce Kwon <bryce@brycekwon.com>
committerBryce Kwon <bryce@brycekwon.com>
commit
parent
tree
download
Rework the response headers in the server configs
Diffstat (limited to 'custom')
-rw-r--r--custom/servers/apache.conf60
-rw-r--r--custom/servers/lighttpd.conf46
-rw-r--r--custom/servers/nginx.conf56
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