Skip to content

Instantly share code, notes, and snippets.

@corburn
Forked from xrstf/letsencrypt.md
Last active September 20, 2023 12:55
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save corburn/9ad9d07535d59b478159 to your computer and use it in GitHub Desktop.
Save corburn/9ad9d07535d59b478159 to your computer and use it in GitHub Desktop.
Nginx server notes

The following is from scotthelme.co.uk

Content Security Policy

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

A browser that supports the Content-Security-Policy header will only download content from domains explicitly allowed. Content-Security-Policy-Report-Only is similar, but only reports violations. Useful during implementation, tuning and testing efforts. Both headers may be sent together allowing for incremental changes to the policy.

Directives cannot be specified twice, as the second will be ignored.

# Wrong - No scripts would be loaded from google
Content-Security-Policy: script-src scotthelme.co.uk; script-src google.com
# Right
Content-Security-Policy: script-src scotthelme.co.uk google.com

There is no inheritance from the default source directive: would result in no scripts being loaded over https from scotthelme.co.uk.

# Wrong - Scripts would not be loaded over https from scotthelme.co.uk
Content-Security-Policy: default-src https:; script-src http://scotthelme.co.uk
# Right
Content-Security-Policy: default-src https:; script-src https://scotthelme.co.uk http://scotthelme.co.uk

Directives

  • self: keyword for the current domain.
  • default-src: Define loading policy for all resources type in case of a resource type dedicated directive is not defined (fallback),
  • script-src: Define which scripts the protected resource can execute,
  • object-src: Define from where the protected resource can load plugins,
  • style-src: Define which styles (CSS) the user applies to the protected resource,
  • img-src: Define from where the protected resource can load images,
  • media-src: Define from where the protected resource can load video and audio,
  • frame-src: Define from where the protected resource can embed frames,
  • font-src: Define from where the protected resource can load fonts,
  • connect-src: Define which URIs the protected resource can load using script interfaces,
  • form-action: Define which URIs can be used as the action of HTML form elements,
  • sandbox: Specifies an HTML sandbox policy that the user agent applies to the protected resource,
  • script-nonce: Define script execution by requiring the presence of the specified nonce on script elements,
  • plugin-types: Define the set of plugins that can be invoked by the protected resource by limiting the types of resources that can be embedded,
  • reflected-xss: Instructs a user agent to activate or deactivate any heuristics used to filter or block reflected cross-site scripting attacks, equivalent to the effects of the non-standard X-XSS-Protection header,
  • report-uri: Specifies a URI to which the user agent sends reports about policy violation

Keywords

  • none blocks the use of this type of resource.
  • self matches the current origin (but not subdomains).
  • unsafe-inline allows the use of inline JS and CSS.
  • unsafe-eval allows the use of mechanisms like eval().

Data

These values specify additional locations assets can be loaded from.

  • data: This allows data: URIs to be used, like base64 encoded images.
  • mediastream: This allows mediastream: URIs to be used.
  • blob: This allows blob: URIs to be used.
  • filesystem: This allows filesystem: URIs to be used.

Hashes

If you want to safely inline script or style without using the 'unsafe-inline' directive you can use a hash value of the script or style to whitelist it. If you are considering using 'unsafe-inline' you should consider using a hash or nonce instead.

sha256-U53QO64URPPK0Fh7tsq0QACAno68LrPc5G6Avyy07xs= This is the result of base64 encoding the binary hash of alert('Hello world!');. Any change in the script whatsoever will alter the resulting hash and the script will not be executed. This will also not whitelist externally hosted scripts, you still need to specify their origin. With this value placed in the script-src directive the browser would execute this inline script if it was placed in the page.

sha256-RB20JxKPtBo78ZjWkZ+GR4yOncuhVeK20jxJPz4x86c= This is the result of base64 encoding the binary hash of color: #e6400c;. Any change in the style whatsoever will alter the resulting hash and the style will not be applied. This will also not whitelist externally hosted styles, you still need to specify their origin. With this value place in the style-src directive the browser would apply this inline style if was placed in the page.

Nonces

If you want to safely inline script or style without using the unsafe-inline directive you can use a nonce value to whitelist the script or style. If you are considering using 'unsafe-inline' you should consider using a hash or nonce instead.

nonce-RANDOM_NONCE_VALUE To use a nonce to whitelist a script on the page you would place the nonce value in the script tag like so: <script nonce="RANDOM_NONCE_VALUE">alert('Hi!');</script> The browser would now execute the script and the same method can be applied to a style tag. The nonce value should be a base64 encode of at least 128 bits of data from a cryptographically secure random number generator.

Note: Using a static nonce is not advised and is actually less secure than using the unsafe-inline directive. If the attacker utilises the nonce value, they can bypass all other restrictions in the CSP and execute any script they like. A nonce must be generated at random with each page load and inserted into the CSP and the DOM.

Clickjacking

The established way of preventing clickjacking involves the use of the header X-Frame-Options (see: Clickjacking_Defense_Cheat_Sheet). However, CSP 2.0 has a new directive frame-ancestors.

Content-Security-Policy: frame-ancestors: 'self' *.example.com

Directives

  • self: keyword for the current domain.
  • default-src: Define loading policy for all resources type in case of a resource type dedicated directive is not defined (fallback),
  • script-src: Define which scripts the protected resource can execute,
  • object-src: Define from where the protected resource can load plugins,
  • style-src: Define which styles (CSS) the user applies to the protected resource,
  • img-src: Define from where the protected resource can load images,
  • media-src: Define from where the protected resource can load video and audio,
  • frame-src: Define from where the protected resource can embed frames,
  • font-src: Define from where the protected resource can load fonts,
  • connect-src: Define which URIs the protected resource can load using script interfaces,
  • form-action: Define which URIs can be used as the action of HTML form elements,
  • sandbox: Specifies an HTML sandbox policy that the user agent applies to the protected resource,
  • script-nonce: Define script execution by requiring the presence of the specified nonce on script elements,
  • plugin-types: Define the set of plugins that can be invoked by the protected resource by limiting the types of resources that can be embedded,
  • reflected-xss: Instructs a user agent to activate or deactivate any heuristics used to filter or block reflected cross-site scripting attacks, equivalent to the effects of the non-standard X-XSS-Protection header,
  • report-uri: Specifies a URI to which the user agent sends reports about policy violation

Keywords

  • none blocks the use of this type of resource.
  • self matches the current origin (but not subdomains).
  • unsafe-inline allows the use of inline JS and CSS.
  • unsafe-eval allows the use of mechanisms like eval().

Data

These values specify additional locations assets can be loaded from.

  • data: This allows data: URIs to be used, like base64 encoded images.
  • mediastream: This allows mediastream: URIs to be used.
  • blob: This allows blob: URIs to be used.
  • filesystem: This allows filesystem: URIs to be used.

Hashes

If you want to safely inline script or style without using the 'unsafe-inline' directive you can use a hash value of the script or style to whitelist it. If you are considering using 'unsafe-inline' you should consider using a hash or nonce instead.

sha256-U53QO64URPPK0Fh7tsq0QACAno68LrPc5G6Avyy07xs= This is the result of base64 encoding the binary hash of alert('Hello world!');. Any change in the script whatsoever will alter the resulting hash and the script will not be executed. This will also not whitelist externally hosted scripts, you still need to specify their origin. With this value placed in the script-src directive the browser would execute this inline script if it was placed in the page.

sha256-RB20JxKPtBo78ZjWkZ+GR4yOncuhVeK20jxJPz4x86c= This is the result of base64 encoding the binary hash of color: #e6400c;. Any change in the style whatsoever will alter the resulting hash and the style will not be applied. This will also not whitelist externally hosted styles, you still need to specify their origin. With this value place in the style-src directive the browser would apply this inline style if was placed in the page.

Nonces

If you want to safely inline script or style without using the unsafe-inline directive you can use a nonce value to whitelist the script or style. If you are considering using 'unsafe-inline' you should consider using a hash or nonce instead.

nonce-RANDOM_NONCE_VALUE To use a nonce to whitelist a script on the page you would place the nonce value in the script tag like so: <script nonce="RANDOM_NONCE_VALUE">alert('Hi!');</script> The browser would now execute the script and the same method can be applied to a style tag. The nonce value should be a base64 encode of at least 128 bits of data from a cryptographically secure random number generator.

Note: Using a static nonce is not advised and is actually less secure than using the unsafe-inline directive. If the attacker utilises the nonce value, they can bypass all other restrictions in the CSP and execute any script they like. A nonce must be generated at random with each page load and inserted into the CSP and the DOM.

Clickjacking

The established way of preventing clickjacking involves the use of the header X-Frame-Options (see: Clickjacking_Defense_Cheat_Sheet). However, CSP 2.0 has a new directive frame-ancestors.



# /etc/nginx/sites-available/default
# https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/
# HTTPS/2 https://bjornjohansen.no/optimizing-https-nginx
#upstream example {
# server backend1.example.com weight=5;
# server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
# server unix:/tmp/backend3;
#
# server backup1.example.com backup;
#}
upstream fastcgi {
server 10.0.3.5:9000;
}
upstream wsbackend {
server 10.0.3.5;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
# letsencrypt webroot certificate renewal.
location ~ .well-known/acme-challenge/ {
root /srv/letsencrypt;
}
# Redirect all HTTP requests to HTTPS with a 301 Moved Permanently response.
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
# Pitfalls and Common Mistakes: Root inside Location Block
root /srv/default;
# Pass PHP scripts to FastCGI server
location ~ \.php$ {
# Pitfalls and Common Mistakes: Passing Uncontrolled Requests to PHP
# TODO: Evaluate the included directives against the Pitfalls and Common mistakes
include snippets/fastcgi-php.conf;
fastcgi_pass fastcgi;
}
# Reverse proxy websockets
# https://www.nginx.com/blog/websocket-nginx/
location /wsapp/ {
proxy_pass http://wsbackend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location / {
# First attempt to serve request as file, then
# as directory, then fallback to displaying a 404.
try_files $uri $uri/ =404;
}
}
# /etc/nginx/snippets/fastcgi-php.conf;
# regex to split $uri to $fastcgi_script_name and $fastcgi_path
fastcgi_split_path_info ^(.+\.php)(/.+)$;
# Check that the PHP script exists before passing it
try_files $fastcgi_script_name =404;
# Bypass the fact that try_files resets $fastcgi_path_info
# see: http://trac.nginx.org/nginx/ticket/321
set $path_info $fastcgi_path_info;
fastcgi_param PATH_INFO $path_info;
fastcgi_index index.php;
include fastcgi.conf;
# TODO: evaluate gzip vulnerabilites
# https://github.com/h5bp/server-configs-nginx/issues/72
# Enable Gzip compressed.
gzip on;
# Compression level (1-9).
# 5 is a perfect compromise between size and cpu usage, offering about
# 75% reduction for most ascii files (almost identical to level 9).
gzip_comp_level 5;
# Don't compress anything that's already small and unlikely to shrink much
# if at all (the default is 20 bytes, which is bad as that usually leads to
# larger files after gzipping).
gzip_min_length 256;
# Compress data even for clients that are connecting to us via proxies,
# identified by the "Via" header (required for CloudFront).
gzip_proxied any;
# Tell proxies to cache both the gzipped and regular version of a resource
# whenever the client's Accept-Encoding capabilities header varies;
# Avoids the issue where a non-gzip capable client (which is extremely rare
# today) would display gibberish if their proxy gave them the gzipped version.
#gzip_vary on;
# Compress all output labeled with one of the following MIME-types.
gzip_types
application/atom+xml
application/javascript
application/json
application/ld+json
application/manifest+json
application/rss+xml
application/vnd.geo+json
application/vnd.ms-fontobject
application/x-font-ttf
application/x-web-app-manifest+json
application/xhtml+xml
application/xml
font/opentype
image/bmp
image/svg+xml
image/x-icon
text/cache-manifest
text/css
text/plain
text/vcard
text/vnd.rim.location.xloc
text/vtt
text/x-component
text/x-cross-domain-policy;
# text/html is always compressed by HttpGzipModule
# This should be turned on if you are going to have pre-compressed copies (.gz) of
# static files available. If not it should be left off as it will cause extra I/O
# for the check. It is best if you enable this in a location{} block for
# a specific directory, or on an individual server{} level.
# gzip_static on;
# /etc/network/interfaces
# See man 5 interfaces
# This file describes the network interfaces available on your
# system and how to activate them. For more information, see
# interfaces(5).
# The loopback network interface
auto lo
iface lo inet loopback
# The primary network interface
auto eth0
iface eth0 inet6 static
address 2001:0DB8::F001
netmask 64
gateway 2001:0DB8::1
autoconf 0
dns-nameservers 2001:4860:4860::8844 2001:4860:4860::8888 8.8.8.8
iface eth0 inet static
address 203.0.113.2
netmask 255.255.255.0
gateway 203.0.113.1
up ip addr add 10.17.0.6/16 dev eth0
#!/bin/sh
nginx_container="10.0.x.x"
iptables -A PREROUTING -i eth0 -p tcp -m tcp --dport 80 -j DNAT --to-destination ${nginx_container}:80
iptables -A PREROUTING -i eth0 -p tcp -m tcp --dport 443 -j DNAT --to-destination ${nginx_container}:443
# TODO: ipv6 routing to containers:
# http://ubuntuforums.org/showthread.php?t=2215702

IPv6

IPv6 is 128 bits long - includes the network address and host id. A mask of \64 means the first 64 bits are the network address.

Link-local address

IPv6 addresses are only useable on the local link (one network leg).

Derived from the MAC address:

  • fe80::::/10
  • extended unique identifier, 64 bits (eui-64)
  • flip the 7th bit and inject FFFE in the middle

IPv4 ARP allowed devices to ask for the L2 (ethernet MAC address) from another local device in the same VLAN. IPv6 does not use ARP or L2 broadcasts; replaced by neighbor discovery protocol, multicast, and Duplicate Address Detection.

Solicited Node Multicast Group

Given a link-local address: FE80::200:11FF:FE11:1111

Joined group addresses:

  • FF02::1
  • FF02::1:FF11:1111

The first is a group joined by any interface that speaks IPv6. The second is joined based on the last 6 bits of the link-local address.

Let's Encrypt on Ubuntu 14.04, nginx with webroot auth

This document details how I setup LE on my server. Firstly, install the client as described on http://letsencrypt.readthedocs.org/en/latest/using.html and make sure you can execute it. I put it in /root/letsencrypt.

As it is not possible to change the ports used for the standalone authenticator and I already have a nginx running on port 80/443, I opted to use the webroot method for each of my domains (note that LE does not issue wildcard certificates by design, so you probably want to get a cert for www.example.com and example.com).

Configuration

For this, I placed config files into etc/letsencrypt/configs, named after <domain>.conf. The files are simple:

# the domain we want to get the cert for (up to 100 per cert)
domains = www.example.com,example.com,...

# increase key size
rsa-key-size = 4096

# this address will receive renewal reminders, IIRC
email = webmaster@example.com

# turn off the ncurses UI, we want this to be run as a cronjob
text = True

# authenticate by placing a file in the webroot (under .well-known/acme-challenge/) and then letting
# LE fetch it
authenticator = webroot
webroot-path = /absolute/path/to/your/webroot/

To generate your first cert, open a shell and execute the letsencrypt-auto script:

# cd /root/letsencrypt
# ./letsencrypt-auto --config /etc/letsencrypt/configs/mydomain.conf certonly
Updating letsencrypt and virtual environment dependencies.......
Running with virtualenv: /root/.local/share/letsencrypt/bin/letsencrypt --config /etc/letsencrypt/configs/mydomain.conf certonly

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/www.xrstf.de/fullchain.pem. Your cert will
   expire on 2016-02-05. To obtain a new version of the certificate in
   the future, simply run Let's Encrypt again.

Note the certonly command: we only want to issue certificates and don't want the client to fiddle with our nginx config.

nginx Integration

Simply update your nginx sites to use the new certificate and private key:

server {
  ...
  
  ssl_certificate /etc/letsencrypt/live/www.xrstf.de/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/www.xrstf.de/privkey.pem;
  
  ...
}

That's it already.

Renewal

I put a script in /etc/cron.monthly:

#!/bin/sh
# Renew letsencypt SSL certs
# 
# Run the script with the --test-cert flag during initial setup/testing
# to avoid hitting the letsencrypt rate limits:
# ./renew-letsencrypt --test-cert

cd /root/letsencrypt
# Update letsencrypt
git pull origin
    
for conf in /etc/letsencrypt/conf.d/*; do
  ./letsencrypt-auto certonly --renew --config "$conf" $@
done
    
# make sure nginx picks them up
service nginx reload

And now I get new certs on the first of every month. Done.

Adding new domains

Simply put new config files into /etc/letsencrypt/configs and run the command mentioned above once to get the initial cert.

Let’s Encrypt has the following rate limits in place:

Names/Certificate is the limit on how many domain names you can include in a single certificate. This is currently limited to 100 names, or websites, per certificate issued. certificates per domain you could run into through repeated re-issuance. This limit measures certificates issued for a given combination of Public Suffix + Domain (a "registered domain"). This is limited to 5 certificates per domain per week.

Registrations/IP address limits the number of registrations you can make in a given time period; currently 500 per 3 hours. This limit should only affect the largest users of Let's Encrypt. Please utilize our staging environment131 if you’re developing an ACME client. Pending Authorizations/Account limits how many times an ACME client can request a domain name be authorized without actually fulfilling on the request itself. This is most commonly encountered when developing ACME clients, and this limit is set to 300 per account per week. Please utilize our staging environment131 if you’re developing an ACME client.

There is no limit to the number of certificates that can be issued to different domains.

https://github.com/perusio/drupal-with-nginx https://github.com/h5bp/server-configs-nginx https://github.com/mozilla/server-side-tls

nginx_container="10.0.3.x"

iptables -A PREROUTING -i eth0 -p tcp -m tcp --dport 80 -j DNAT --to-destination ${nginx_container}:80
iptables -A PREROUTING -i eth0 -p tcp -m tcp --dport 443 -j DNAT --to-destination ${nginx_container}:443

ip6tables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination [fec0::1234]:80
ip6tables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j DNAT --to-destination [fec0::1234]:443

Suricata Intrusion Detection System

Autoblock malicious IP's, Beware source IP can be spoofed. http://www.fail2ban.org/wiki/index.php/Main_Page

ifconfig eth0 192.168.1.5 netmask 255.255.255.0 up
route add default gw 192.168.1.1
echo "nameserver 4.2.2.2" > /etc/resolv.conf

Google DNS

  • 8.8.8.8
  • 8.8.4.4

Open DNS

  • 208.67.222.222
  • 208.67.220.220

To give LXC containers on lxcbr0 a persistent IP address based on domain name:

  1. Uncomment the following line in /etc/default/lxc-net:

    LXC_DHCP_CONFILE=/etc/lxc/dnsmasq.conf
    
  2. Write entries such as the following in /etc/lxc/dnsmasq.conf:

    dhcp-host=lxcmail,10.0.3.100
    dhcp-host=ttrss,10.0.3.101
    
  3. Changes will become effective after you have restarted lxc-net (which restarts dnsmasq):

    service lxc-net restart
    
  4. Afterwards you can modify /etc/lxc/dnsmasq-hosts.conf and send the SIGHUP signal to dnsmasq:

    killall -s SIGHUP dnsmasq
    
# /etc/network/interfaces
# ...
auto br0
iface br0 inet static
    address 172.31.31.35
    netmask 255.255.255.0
    gateway 172.31.31.2
    dns-nameservers 8.8.8.8 8.8.4.4
    bridge_ports eth0
    bridge_stp off
    bridge_fd 0
    bridge_maxwait 0
$ lxc profile create bridged
$ lxc profile edit bridged
name: bridged
config: {}
devices:
  eth0:
    nictype: bridged
    parent: br0
    type: nic
# add the namespaces
ip netns add ns1
ip netns add ns2

ip link add mv1 link eth0 type macvlan mode bridge
ip link add mv2 link eth0 type macvlan mode bridge

ip link set mv1 netns ns1
ip link set mv2 netns ns2

ip netns exec ns1 ip link set dev mv1 up
ip netns exec ns2 ip link set dev mv2 up

## set ip addresses
ip netns exec ns1 ifconfig mv1 10.10.10.1/24 up
ip netns exec ns2 ifconfig mv2 10.10.10.2/24 up

ns1 and ns2 should be reachable via icmp at this point.

Config

Container Start on Boot: $ lxc config set my_container boot.autostart true

# /etc/nginx/conf.d/mime.types
# https://github.com/h5bp/server-configs-nginx
types {
# Data interchange
application/atom+xml atom;
application/json json map topojson;
application/ld+json jsonld;
application/rss+xml rss;
application/vnd.geo+json geojson;
application/xml rdf xml;
# JavaScript
# Normalize to standard type.
# https://tools.ietf.org/html/rfc4329#section-7.2
application/javascript js;
# Manifest files
application/manifest+json webmanifest;
application/x-web-app-manifest+json webapp;
text/cache-manifest appcache;
# Media files
audio/midi mid midi kar;
audio/mp4 aac f4a f4b m4a;
audio/mpeg mp3;
audio/ogg oga ogg opus;
audio/x-realaudio ra;
audio/x-wav wav;
image/bmp bmp;
image/gif gif;
image/jpeg jpeg jpg;
image/png png;
image/svg+xml svg svgz;
image/tiff tif tiff;
image/vnd.wap.wbmp wbmp;
image/webp webp;
image/x-jng jng;
video/3gpp 3gp 3gpp;
video/mp4 f4p f4v m4v mp4;
video/mpeg mpeg mpg;
video/ogg ogv;
video/quicktime mov;
video/webm webm;
video/x-flv flv;
video/x-mng mng;
video/x-ms-asf asf asx;
video/x-ms-wmv wmv;
video/x-msvideo avi;
# Serving `.ico` image files with a different media type
# prevents Internet Explorer from displaying then as images:
# https://github.com/h5bp/html5-boilerplate/commit/37b5fec090d00f38de64b591bcddcb205aadf8ee
image/x-icon cur ico;
# Microsoft Office
application/msword doc;
application/vnd.ms-excel xls;
application/vnd.ms-powerpoint ppt;
application/vnd.openxmlformats-officedocument.wordprocessingml.document docx;
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx;
application/vnd.openxmlformats-officedocument.presentationml.presentation pptx;
# Web fonts
application/font-woff woff;
application/font-woff2 woff2;
application/vnd.ms-fontobject eot;
# Browsers usually ignore the font media types and simply sniff
# the bytes to figure out the font type.
# https://mimesniff.spec.whatwg.org/#matching-a-font-type-pattern
#
# However, Blink and WebKit based browsers will show a warning
# in the console if the following font types are served with any
# other media types.
application/x-font-ttf ttc ttf;
font/opentype otf;
# Other
application/java-archive ear jar war;
application/mac-binhex40 hqx;
application/octet-stream bin deb dll dmg exe img iso msi msm msp safariextz;
application/pdf pdf;
application/postscript ai eps ps;
application/rtf rtf;
application/vnd.google-earth.kml+xml kml;
application/vnd.google-earth.kmz kmz;
application/vnd.wap.wmlc wmlc;
application/x-7z-compressed 7z;
application/x-bb-appworld bbaw;
application/x-bittorrent torrent;
application/x-chrome-extension crx;
application/x-cocoa cco;
application/x-java-archive-diff jardiff;
application/x-java-jnlp-file jnlp;
application/x-makeself run;
application/x-opera-extension oex;
application/x-perl pl pm;
application/x-pilot pdb prc;
application/x-rar-compressed rar;
application/x-redhat-package-manager rpm;
application/x-sea sea;
application/x-shockwave-flash swf;
application/x-stuffit sit;
application/x-tcl tcl tk;
application/x-x509-ca-cert crt der pem;
application/x-xpinstall xpi;
application/xhtml+xml xhtml;
application/xslt+xml xsl;
application/zip zip;
text/css css;
text/html htm html shtml;
text/mathml mml;
text/plain txt;
text/vcard vcard vcf;
text/vnd.rim.location.xloc xloc;
text/vnd.sun.j2me.app-descriptor jad;
text/vnd.wap.wml wml;
text/vtt vtt;
text/x-component htc;
}
# /etc/nginx/nginx.conf
#http {
#
# ##
# # Basic Settings
# ##
#
# # Pitfalls and Common Mistakes: Multiple Index Directives
# index index.php index.htm index.html;
#
# tcp_nodelay on;
# types_hash_max_size 2048;
#
# # server_names_hash_bucket_size 64;
# # server_name_in_redirect off;
#
# ##
# # Gzip Settings
# ##
#
# # TODO: evaluate gzip vulnerabilites
# # https://github.com/h5bp/server-configs-nginx/issues/72
#
# gzip_disable "msie6";
#
# # gzip_buffers 16 8k;
# # gzip_http_version 1.1;
#
# # Restrict Allowed HTTP methods
# # https://bjornjohansen.no/restrict-allowed-http-methods-in-nginx
# #if ( $request_method !~ ^(GET|POST|HEAD)$ ) {
# # return 405;
# #}
# # Only send Allow header with 405 Method Not Allowed status code.
# #error_page 405 @error405;
# #location @error405 {
# # add_header Allow "GET, POST, HEAD";
# #}
#}
#mail {
# # See sample authentication script at:
# # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
#
# # auth_http localhost/auth.php;
# # pop3_capabilities "TOP" "USER";
# # imap_capabilities "IMAP4rev1" "UIDPLUS";
#
# server {
# listen localhost:110;
# protocol pop3;
# proxy on;
# }
#
# server {
# listen localhost:143;
# protocol imap;
# proxy on;
# }
#}
# nginx Configuration File
# http://wiki.nginx.org/Configuration
# Run as a less privileged user for security reasons.
user www-data www-data;
# How many worker threads to run;
# "auto" sets it to the number of CPU cores available in the system, and
# offers the best performance. Don't set it higher than the number of CPU
# cores if changing this parameter.
# The maximum number of connections for Nginx is calculated by:
# max_clients = worker_processes * worker_connections
worker_processes auto;
# Maximum open file descriptors per process;
# should be > worker_connections.
worker_rlimit_nofile 8192;
events {
# When you need > 8000 * cpu_cores connections, you start optimizing your OS,
# and this is probably the point at which you hire people who are smarter than
# you, as this is *a lot* of requests.
worker_connections 8000;
#multi_accept on;
}
# Default error log file
# (this is only used when you don't override error_log on a server{} level)
#error_log logs/error.log warn;
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
http {
# Pitfalls and Common Mistakes: Multiple Index Directives
index index.php index.htm index.html;
# Don't send the nginx version number in error pages and Server header
server_tokens off;
# Define the MIME types for files.
#include mime.types;
include /etc/nginx/conf.d/mime.types;
default_type application/octet-stream;
# Update charset_types due to updated mime.types
charset_types text/css text/plain text/vnd.wap.wml application/javascript application/json application/rss+xml application/xml;
# Format to use in log files
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# Default log file
# (this is only used when you don't override access_log on a server{} level)
# It is thus a good idea to specify both root and access_log on the same level: http://nginx.org/en/docs/http/ngx_http_log_module.html#access_log
#access_log logs/access.log main;
access_log /var/log/nginx/access.log;
# How long to allow each connection to stay idle; longer values are better
# for each individual client, particularly for SSL, but means that worker
# connections are tied up longer. (Default: 65)
keepalive_timeout 20;
# Speed up file transfers by using sendfile() to copy directly
# between descriptors rather than using read()/write().
# For performance reasons, on FreeBSD systems w/ ZFS
# this option should be disabled as ZFS's ARC caches
# frequently used files in RAM by default.
sendfile on;
# Tell Nginx not to send out partial frames; this increases throughput
# since TCP frames are filled up before being sent out. (adds TCP_CORK)
tcp_nopush on;
# Include files in the sites-enabled folder. server{} configuration files should be
# placed in the sites-available folder, and then the configuration should be enabled
# by creating a symlink to it in the sites-enabled folder.
# See doc/sites-enabled.md for more info.
include /etc/nginx/conf.d/*;
include /etc/nginx/sites-enabled/*;
}
# /etc/nginx/conf/owasp-useful-headers.conf
# https://www.owasp.org/index.php/List_of_useful_HTTP_headers
# The Public Key Pinning Extension for HTTP (HPKP) is a security header that tells a web client to associate a specific
# cryptographic public key with a certain web server to prevent MITM attacks with forged certificates.
# TODO: enable
# 2592000 seconds == 30 days
#add_header Public-Key-Pins "pin-sha256="<sha256>"; pin-sha256="<sha256>"; max-age=2592000; includeSubDomains" always;
# rfc6797 HTTP Strict Transport Security (HSTS)
# The browser should always access the site over a secure connection without needing a redirect.
# 31536000 seconds == 1 year
# 10886400 seconds == 18 weeks ( minimum required by Mozilla and Chrome for HSTS preload )
# includeSubdomains token is optional and should only be defined if the SSL key is used for all subdomains.
# preload token indicates consent to have the site included in browser HSTS preload lists
# Register for browser HSTS preload: https://hstspreload.appspot.com/
# An HSTS Host MUST NOT include the STS header field in HTTP responses conveyed over non-secure transport: https://tools.ietf.org/html/rfc6797#section-7.2
#add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# 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;
add_header X-Frame-Options deny 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;
# 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.
# 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;
#add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://ssl.google-analytics.com https://assets.zendesk.com https://connect.facebook.net; img-src 'self' https://ssl.google-analytics.com https://s-static.ak.facebook.com https://assets.zendesk.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://assets.zendesk.com; font-src 'self' https://themes.googleusercontent.com; frame-src https://assets.zendesk.com https://www.facebook.com https://s-static.ak.facebook.com https://tautt.zendesk.com; object-src 'none'" always;
add_header Content-Security-Policy "upgrade-insecure-requests; report-uri https://report-uri.io/report/corburn" always;
#add_header Content-Security-Policy-Report-Only "default-src https:; report-uri https://report-uri.io/report/corburn/reportOnly" always;
add_header Content-Security-Policy-Report-Only "report-uri https://report-uri.io/report/corburn/reportOnly; default-src 'self' *.example.com; form-action 'self' *.example.com; frame-ancestors 'self' *.example.com; base-uri: 'self' *.example.com; block-all-mixed-content; upgrade-insecure-requests" always;
# Mark all cookies secure and HttpOnly.
# The secure attribute instructs the browser to only send cookies through an encrypted HTTPS connection.
# The HttpOnly attribute instructs the browser to not allow scripts to access cookies via the DOM document.cookie object;
# this is mandatory to prevent session ID stealing through XSS attacks.
# https://www.owasp.org/index.php/Session_Management_Cheat_Sheet
#Set-Cookie: Key=Value; path=/; secure; HttpOnly, Key2=Value2; secure; HttpOnly
# Caution must be taken to avoid cacheing private information, especially in intermediate caches.
# no-store: the response should not be cached by the browser or any intermediate cache.
# no-cache: the response may be cached, but the Etag should always be verified with the server to see if the resource has changed.
# public: the response may always be cached by the browser and intermediate caches.
# private: the response may be cached by the browser.
# https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching
add_header Cache-Control "public, max-age=600";
# /etc/nginx/conf/ssl.conf
# Test configuration with:
# ssllabs.com/ssltest
# httpsecurityreport.com
# securityheaders.io
#
# https://developers.google.com/speed/pagespeed/insights/
ssl_certificate /etc/letsencrypt/live/chirabisu.xyz/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/chirabisu.xyz/privkey.pem;
ssl_session_cache shared:SSL:20m;
ssl_session_timeout 60m;
# Disable weak ciphers
ssl_prefer_server_ciphers on;
ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
# Generate DH parameters file
# openssl dhparam 2048 -out /etc/nginx/cert/dhparam.pem
# https://wiki.mozilla.org/Security/Server_Side_TLS#DHE_handshake_and_dhparam
ssl_dhparam /etc/nginx/cert/dhparam.pem;
# Disable deprecated SSL protocols ref: POODLE
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_stapling on;
ssl_stapling_verify on;
#ssl_trusted_certificate /etc/nginx/cert/trustchain.crt;
resolver 8.8.8.8 8.8.4.4;
@urko-b
Copy link

urko-b commented Mar 8, 2023

Hi, thanks so much for your content. Could you please help me how could I use owasp-useful-headers.conf? Kind regards

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment