Understanding what it means to have a safe site.
learning how to harden
December 3, 2024 (Updated: December 3, 2024)
In this post we’ll be looking at how to secure our site from threats
Prerequisites
Software Needed
- Command Prompt : For talking to my server via SSH and running simple commands
- Nginx : The web server used for hosting the site
- Certbot : For obtaining and managing SSL/TLS certificates
Technical Skills
Basic knowledge of:
- using command line
- Configuring Nginx
- Editing configuration files using a text editor
Accounts and Services
- Access to the server via SSH
- A registered domain name pointing to the server
- An account with sudo privileges for administrative tasks
Step-by-Step Guide
Step 1. Install Certbot and Dependencies
- Update the Package List:
bash
sudo apt update
- Install Certbot an Nginx Plugin:
- Certbot automates the process of obtaining and renewing SSL certificates from Let’s Encrypt
bash
Sudo apt install certbot python-certbot-nginx -y
Step 2. Obatin an SSL certificates
- Verify Nginx Configuration
- Ensure you Nginx configuration is valid before proceeding
bash
Sudo nignx -t
- Obtain SSL Certificate:
- Run certbot to generate and install the certificate
bash
Sudo certbot --nginx -d yourdomain.com
- Certbot will automatically Update your Nginx configuration to include the SSL settings
- Verify Certificate Installation: Open your website in a browser and ensure it loads HTTPS (look for the padlock in the address bar)
Step 3. Automate SSL Certificate Renewal
- test Automatic Renewal Certbot includes a timer for automatic renewal to test:
bash
sudo certbot renew --dry-run
- confirm Renewal if the test passes, Certbot will handle automatic renewals
Step 4. Configure Nginx Security Headers
- Edit your Nginx Configuration:
- Open the configuration file for your domain
bash
sudo nano /etc/nginx/sites-available/yourdomain
- Add the following Security Headers: inside the server block add these lines
nginx
# Enforce HTTPS and protect against downgrade attacks
# max-age=31536000: Cache the policy for 1 year
# includeSubDomains: Apply the policy to all subdomains
# preload: Indicate to browsers to preload this site as HTTPS-only
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# Define a strict Content Security Policy (CSP) to restrict the resources that can be loaded
# default-src 'self': Only allow resources from the same origin
# script-src 'self': Restrict JavaScript to same-origin
# style-src 'self': Restrict CSS to same-origin
# img-src 'self' data:: Allow images from same-origin or inline data URIs
# object-src 'none': Block plugins like Flash or Java
# font-src 'self': Restrict fonts to same-origin
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; object-src 'none'; font-src 'self';" always;
# Prevent browsers from interpreting files as a different MIME type
add_header X-Content-Type-Options "nosniff" always;
# Block all framing of the site to prevent clickjacking attacks
add_header X-Frame-Options "DENY" always;
# Enable XSS filtering and block detected attacks
add_header X-XSS-Protection "1; mode=block" always;
# Restrict what information is shared in the `Referer` header
# no-referrer-when-downgrade: Send the Referer header unless navigating to an insecure HTTP URL
add_header Referrer-Policy "no-referrer-when-downgrade" always;
# Define permissions for browser features
# geolocation=(self): Only allow geolocation on the same origin
# microphone=(self): Only allow microphone access on the same origin
# camera=(self): Only allow camera access on the same origin
add_header Permissions-Policy "geolocation=(self), microphone=(self), camera=(self)" always;
# Disable caching for sensitive content to protect privacy
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate" always;
# Allow cross-origin requests (CORS)
# Access-Control-Allow-Origin "*": Allow requests from any origin
# Access-Control-Allow-Methods: Specify allowed HTTP methods
# Access-Control-Allow-Headers: Specify allowed HTTP headers
add_header Access-Control-Allow-Origin "*";
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept";
- Test Nginx Configuation:
- Check for syntax errors:
bash
sudo nginx -t
- Reload Nginx: Apply the changes
sudo systemctl reload nginx
Step. 5 Verify Security Headers
- Use Online Tools:
- Test your site for security headers using Securityheaders.com or similar tools
- Inspect Headers in Browser
- Open site in browser
- Use dev tools (F12) to inspect reponse headers in the network tab
Step. 6 Trouble Shooting Common Issues
- Nginx fails to reload due to a configuragtion error
- Run sudo nginx -t to identify and fix syntax issues before reloading with sudo systemctl reload nginx
- Certbot fails to obtain a SSL certificate
- Verify DNS records are correct and ensure port 80 is open using sudo ufw allow 80.
- Security headers do not appear in responses
- Check the Nginx configuration for header settings make sure they are in the right server block and reload Nginx using sudo systemctl reload nginx.