I have a Laravel site running nginx 1.15.0. The site config specifies HSTS (HTTP Strict Transport Security) headers at the server level. This works just fine for all valid URLs.
However, when requesting a resource that results in a 404, the HSTS header is not returned with the response. This is also true of other headers set by add_header in the server block.
What I'm trying to do is get the HSTS header included even in all responses, even for an error. To be honest, it's just to satisfy the security scanners flagging it as a medium-level vulnerability. It may be security theater, but I'd still like to understand what's going on here.
With one explicitly-defined exception for .json URLs, there are no other add_header directives that would be interfering with those in the server level.
Here is the content of my nginx configuration for this site. The includes before/* and after/* do not appear to be issuing any add_header directives so I'm not expanding those here.
# FORGE CONFIG (DOT NOT REMOVE!)
include forge-conf/example.com/before/*;
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name .example.com;
root /home/forge/example.com/current/public;
client_max_body_size 100M;
# FORGE SSL (DO NOT REMOVE!)
ssl_certificate /etc/nginx/ssl/example.com/302491/server.crt;
ssl_certificate_key /etc/nginx/ssl/example.com/302491/server.key;
ssl_protocols TLSv1.2;
# Updated cipher suite per Mozilla recommendation for Modern compatibility
# https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/nginx/dhparams.pem;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff";
add_header Vary "Origin";
add_header Access-Control-Allow-Origin "*";
add_header Access-Control-Allow-Credentials 'true';
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
add_header Referrer-Policy "strict-origin-when-cross-origin";
add_header Public-Key-Pins 'pin-sha256="hpkppinhash="; pin-sha256="anotherpinhash="; pin-sha256="yetanotherpinhash="; pin-sha256="anotherpinhash="; pin-sha256="lastpinhash="; max-age=86400';
index index.html index.htm index.php;
charset utf-8;
# FORGE CONFIG (DOT NOT REMOVE!)
include forge-conf/example.com/server/*;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log off;
error_log /var/log/nginx/example.com-error.log error;
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php7.1-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
location ~* \.json {
add_header Cache-Control "no-store,no-cache";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
add_header Referrer-Policy "strict-origin-when-cross-origin";
}
}
# FORGE CONFIG (DOT NOT REMOVE!)
include forge-conf/example.com/after/*;
You need to add the always parameter as stated in the documentation:
Adds the specified field to a response header provided that the response code equals 200, 201 (1.3.10), 204, 206, 301, 302, 303, 304, 307 (1.1.16, 1.0.13), or 308 (1.13.0). The value can contain variables.
...
If the always parameter is specified (1.7.5), the header field will be added regardless of the response code.
So change your config to this:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
Related
I have a multi-tenancy app hosted on DO. Users are able to create subdomains and also set their preferred custom domain. Need help in setting up the right Nginx config, here is the current one:
Requirements:
1- User setup for their required subdomain on app's domain (with SSL) - WORKING
2- User setup for their own custom domain - for this I have set up an A record to the server IP and below is the Nginx config - NOT WORKING
3- User custom domain is loaded with SSL - need help on how to structure this? Would an A record suffice?
#FORGE CONFIG (DO NOT REMOVE!)
include forge-conf/wiki.pk/before/*;
server {
listen 80;
listen [::]:80;
server_name .one.com "";
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name .one.com "";
#server_name ~.;
#server_name _;
#server_name ~^(?.*)$;
server_tokens off;
root /home/forge/one.com/public;
#FORGE SSL (DO NOT REMOVE!)
ssl_certificate /etc/nginx/ssl/one.com/1233982/server.crt;
ssl_certificate_key /etc/nginx/ssl/one.com/1233982/server.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_dhparam /etc/nginx/dhparams.pem;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.html index.htm index.php;
charset utf-8;
#FORGE CONFIG (DO NOT REMOVE!)
include forge-conf/one.com/server/*;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log off;
error_log /var/log/nginx/one.com-error.log error;
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php8.0-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
#FORGE CONFIG (DO NOT REMOVE!)
include forge-conf/one.com/after/*;
Would appreciate all the help.
For my backend API application I have Laravel 6 with Laravel Passport oAuth2 plugin. Im my routes/web.php I'm using Auth::routes(); to make all oAuth routes. My Nginx config (Running on Amazon instance):
/etc/nginx/conf.d/app.conf
server {
server_name my-app-domain.net;
listen 80;
client_max_body_size 20M;
include /etc/nginx/default.d/*.conf;
root /var/www/app/public;
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.html index.php;
location ~ /\. {
deny all;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
error_page 404 /index.php;
error_page 500 502 503 504 /index.php;
location ~* \.(?:ico|css|otf|gif|jpe?g|png)$ {
expires 30d;
add_header Pragma public;
add_header Cache-Control "public";
root /var/www/app/public;
}
location ~ \.php$ {
fastcgi_index index.php;
fastcgi_pass unix:/run/php-fpm/www.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
}
If I send POST with grant_type and other login credentials to http://<domain name>/oauth/token I'm getting this weird ERROR:
"Symfony \ Component \ HttpKernel \ Exception \
MethodNotAllowedHttpException The GET method is not supported for this
route. Supported methods: POST."
Aside from that the other API requests are working fine, so probably its not a CORS restrictions
However if I run php artisan serve and send POST to http://localhost:8080/oauth/token it works as expected
I was wrong about CORS. Despite I have installed barryvdh/laravel-cors package and settings are set to "*" the CORS was still the issue. So I had to tweak a bit Nginx
server {
server_name my-app-domain.net;
listen 80;
client_max_body_size 20M;
include /etc/nginx/default.d/*.conf;
root /var/www/app/public;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Headers' '*' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always;
index index.html index.php;
charset utf-8;
.....
Plugin barryvdh/laravel-cors has to be deleted as well
I'm running a static built nuxt.js app on my server. It uses the nuxt auth module for authentificating against my laravel backend which runs laravel passport.
My auth-strategy looks like this:
auth: {
strategies: {
'laravel.passport': {
url: 'https://correct_url',
//client_id: 1, //for local use
//client_secret: 'CLIENTSECRET1', //for local use
client_id: 2,
client_secret: 'CLIENTSECRET2',
userinfo_endpoint: 'https://correct_url/oauth/me'
}
}
},
In my local environment (yarn run dev) everything runs fine. After I built and deployed my nuxt-app (yarn run build) the authentification process comes to the authorisation step (where I can click "Authorize" or "cancel"). After I click "Authorize" browser redirects to my nuxt-app but requests still give me:
{"message":"Unauthenticated."}
After a few investigations the only possible cause for this could be the nginx-site which is automatically created through laravel forge. Config looks like this:
# FORGE CONFIG (DO NOT REMOVE!)
include forge-conf/correct_url/before/*;
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name correct_url;
root /home/forge/correct_url/dist;
# FORGE SSL (DO NOT REMOVE!)
ssl_certificate /etc/nginx/ssl/correct_url/589448/server.crt;
ssl_certificate_key /etc/nginx/ssl/correct_url/589448/server.key;
ssl_protocols TLSv1.2;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/nginx/dhparams.pem;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.html index.htm index.php;
charset utf-8;
# FORGE CONFIG (DO NOT REMOVE!)
include forge-conf/correct_url/server/*;
location / {
try_files $uri $uri/ /index.html;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log off;
error_log /var/log/nginx/correct_url-error.log error;
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
# FORGE CONFIG (DO NOT REMOVE!)
include forge-conf/correct_url/after/*;
is there something I overlooked or am I on the wrong path?
I have set up and brand new server with forge and install a bitbucket repo
Forge nginx set up looks like this
# FORGE CONFIG (DOT NOT REMOVE!)
include forge-conf/default/before/*;
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name default;
root /home/forge/default/public;
# FORGE SSL (DO NOT REMOVE!)
# ssl_certificate;
# ssl_certificate_key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!3DES';
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/nginx/dhparams.pem;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.html index.htm index.php;
charset utf-8;
# FORGE CONFIG (DOT NOT REMOVE!)
include forge-conf/default/server/*;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log off;
error_log /var/log/nginx/default-error.log error;
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
# FORGE CONFIG (DOT NOT REMOVE!)
include forge-conf/default/after/*;
On page load I'm getting a 403 error for the load of the site
Any ideas?
I followed the same process over and over. The project going in is a Laravel project , have run the normal composer and NPM installs.
I've been fighting with this for a while now ans still cannot get it to run. I got nginx running on opensuse tumbleweed with codeigniter application.
I get to the front page with no problem but any attempt open a controller fails with 404 error.
When I was working on Ubuntu I was able to solve this within minutes with a little bit of googling, but here for some reason I am struggling. I am attaching my default config file for nginx. There must be something I am really not seeing here, since I got this working in the past. Is nginx on opensuse really such a pain?
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html/;
index index.php;
#charset koi8-r;
#access_log /var/log/nginx/log/host.access.log main;
location / {
root /usr/share/nginx/html/;
index index.php index.html index.htm;
## Handling of CORS
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
#
# Om nom nom cookies
#
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
#
# Custom headers and headers various browsers *should* be OK with but aren't
#
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
#
# Tell client that this pre-flight info is valid for 20 days
#
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
#fastcgi_ignore_client_abort off;
}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
location ~ /\.ht {
deny all;
}
}
Right, I eventually found and answer to the problem. I have pretty much completely erased the the contents of the config file and replaced them with what I found on nginx website (here).
Funny thing is, if you notice there are no more directives for handling CORS in the config file, yet all the contents such as fonts, scripts, etc. are working fine without a glitch on localhost.
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
autoindex on;
index index.php;
location / {
try_files $uri $uri/ /index.php;
location = /index.php {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html$fastcgi_script_name;
include fastcgi_params;
}
}
location ~ \.php$ {
return 444;
}
}
Hope that will be of use to someone ;)