I'm currently trying to learn more about nginx and the given security as a webserver. My imaginary setup is nginx with 3 virtual hosts. Each of these hosts is running a blog.
After working through some hardening tutorials for nginx, I did find myself stuck at those http-headers
... I'm not sure if enforcing content security policy through nginx is the right way if I have multiple virtual hosts, which could depend on different content from different sites.
However my position at the moment is to figure out how to set up a reasonable content security policy whitelist for nginx in every *-src
parameter.
Neither directive reference and source list reference nor
the latest content security policy level 3 did answer the question of a "best practice whitelist" for all *-src
.
Let's say I've put 'self'
on every of those parameters:
default-src
:This is the only parameter that would make sense if set to 'self'
script-src
, style-src
, img-src
, connect-src
, font-src
, child-src
:The rest is giving me a real headache. How am I supposed to know every good source? If I set those to 'self'
will the users always get a 400 HTTP
Error?
Like I said earlier I'm not sure if enforcing content security policy through nginx is the right way. If I'm running a webserver with like 5+ clients it would be impossible for me to know every "good" source for those clients. Again I want to point out that I am just wondering about these source parameters. The other HTTP-Headers (not only content security policy) make sense for me and are completely reasonable.
Regards, Megajin
Once the page source is shown, find out whether a CSP is present in a meta tag. Conduct a find (Ctrl-F on Windows, Cmd-F on Mac) and search for the term “Content-Security-Policy”. If “Content-Security-Policy” is found, the CSP will be the code that comes after that term.
The Nginx add_header directive allows you to define an arbitrary response header and value to be included in all response codes, which are equal to 200 , 201 , 204 , 206 , 301 , 302 , 303 , 304 , or 307 . This can be defined from within your nginx.
UPDATE: After some more research
I did find a very helpful Repo on Github. Which I'll share with you guys.
Short description: Nginx Server Configs is a collection of configuration snippets that can help your server improve the web site's performance and security, while also ensuring that resources are served with the correct content-type and are accessible, if needed, even cross-domain.
Link to Repo: https://github.com/h5bp/server-configs-nginx
However I recommend you to read and learn about every single option! I still use my own CSP Policy like I showed below in my original answer. I thought this information might be useful for any beginner in the nginx universe.
I went and did some more research on my problem. At the moment I'm good with my configuration which I will share at the bottom of this post.
This Stackoverflow question was actually a good starting point: How does Content Security Policy work?
My last standing point is to secure everything and if any of the users is getting a CSP - Error they have to tell the server admin that they want to add another source to the CSP. If the source seems trustworthy it will be added, else rejected (I might automate that process somehow).
If someone is interested in further SSL configuration you can look up this github page: https://gist.github.com/plentz/6737338
Here is my nginx header config (updated headers according to update on 22nd July 2019 - see below):
# don't send the nginx version number in error pages and Server header
server_tokens off;
# config to don't allow the browser to render the page inside an frame or iframe
# and avoid clickjacking http://en.wikipedia.org/wiki/Clickjacking
# if you need to allow [i]frames, you can use SAMEORIGIN or even set an uri with ALLOW-FROM uri
# https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options
add_header X-Frame-Options SAMEORIGIN always;
# when serving user-supplied content, include a X-Content-Type-Options: nosniff header along with the Content-Type: header,
# to disable content-type sniffing on some browsers.
# https://www.owasp.org/index.php/List_of_useful_HTTP_headers
# currently suppoorted in IE > 8 http://blogs.msdn.com/b/ie/archive/2008/09/02/ie8-security-part-vi-beta-2-update.aspx
# http://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx
# 'soon' on Firefox https://bugzilla.mozilla.org/show_bug.cgi?id=471020
add_header X-Content-Type-Options nosniff always;
# This header enables the Cross-site scripting (XSS) filter built into most recent web browsers.
# It's usually enabled by default anyway, so the role of this header is to re-enable the filter for
# this particular website if it was disabled by the user.
# https://www.owasp.org/index.php/List_of_useful_HTTP_headers
add_header X-XSS-Protection "1; mode=block" always;
# with Content Security Policy (CSP) enabled(and a browser that supports it(http://caniuse.com/#feat=contentsecuritypolicy),
# you can tell the browser that it can only download content from the domains you explicitly allow
# http://www.html5rocks.com/en/tutorials/security/content-security-policy/
# https://www.owasp.org/index.php/Content_Security_Policy
# I need to change our application code so we can increase security by disabling 'unsafe-inline' 'unsafe-eval'
# directives for css and js(if you have inline css or js, you will need to keep it too).
# more: http://www.html5rocks.com/en/tutorials/security/content-security-policy/#inline-code-considered-harmful
add_header Content-Security-Policy "default-src 'self' https://google.com https://youtube.com https://facebook.com https://fonts.google.com https://fonts.googleapis.com https://ajax.googleapis.com https://www.google-analytics.com https://cdnjs.cloudflare.com https://code.jquery.com https://connect.facebook.net https://s.imgur.com https://imgur.com https://i.imgur.com https://500px.com https://drscdn.500px.org https://www.reddit.com https://www.flickr.com https://c1.staticflickr.com https://maxcdn.bootstrapcdn.com http://code.ionicframework.com https://cdn.fontawesome.com/; script-src 'self' 'unsafe-inline'; style-src 'self'; img-src 'self' data:; connect-src 'self'; font-src 'self'; object-src 'none'; media-src 'self'; form-action 'self'; frame-ancestors 'self';" always;
This will be a long learning process with the help of my users. I hope this will help someone else too.
Update 22nd July 2019
As stated in the comments, under certain circumstances the headers
will be shown but ignored after the first line. Please be careful because:
nginx treats the white space between the quotes literally, so as long as you begin each new line with a space or tab character, the header will remain valid.
NOTE:
The support for splitting header lines is deprecated in RFC 7230:
From RFC 7230 section 3.2.4
Historically, HTTP header field values could be extended over
multiple lines by preceding each extra line with at least one space
or horizontal tab (obs-fold). This specification deprecates such
line folding except within the message/http media type
The safest solution would be to accept that some lines in your configuration file may be very much longer than you would prefer.
Source for the update: https://stackoverflow.com/a/50043114/4457744
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With