Off-By-Slash
i.e.
location /api {
proxy_pass http://apiserver/v1/;
}
request
http://server/api/user -> http://apiserver/v1//user
/../
# Nginx normalize "/v1/../" to "/"
http://server/api../ -> http://apiserver/v1/../ -> http://apiserver/
風險
Apache server-status being exposed with the URL http://server/api../server-status
Checking
http://server/api/user -> http://apiserver/v1//user
http://server/apiuser -> http://apiserver/v1/user
Missing "root" location on "server {...}" block
If you add a root to every location block then a location block that isn’t matched will have no root.
server { server_name www.example.com; location / { root /var/www/nginx-default/; # [...] } location /foo { root /var/www/nginx-default/; # [...] } }
Server Name (If)
Since you’re requesting NGINX to check for the Host header for every request, it’s extremely inefficient.
server { server_name example.com *.example.com; if ($host ~* ^www\.(.+)) { set $raw_domain $1; rewrite ^/(.*)$ $raw_domain/$1 permanent; } # [...] } }
建議做法
server { server_name www.example.com; return 301 $scheme://example.com$request_uri; } server { server_name example.com; # [...] }
Incorrect return context
The return directive applies only inside the topmost context it’s defined in.
A request to /a/test.html will return a 301.
server { location /a/ { try_files test.html =404; } return 301 http://example.org; }
Passing Uncontrolled Requests to PHP
[1] Proxy Everything
server { server_name _; root /var/www/site; location / { include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_pass unix:/tmp/phpcgi.socket; } }
[2]
當 non-exist.php 不存在時, php 會嘗試執行 exist.jpg
location ~* \.php$ { #/forum/avatar/exist.jpg/non-exist.php fastcgi_pass backend; ... }
php setting
Set cgi.fix_pathinfo=0 in php.ini.
This causes the PHP interpreter to only try the literal path given and to stop processing if the file is not found.
i.e.
http://example.com/path/to/script.php/THIS/IS/PATH/INFO?query_args=foo
SCRIPT_FILENAME gets "/path/to/script.php" PATH_INFO gets "/THIS/IS/PATH/INFO" QUERY_STRING gets "query_args=foo"
cgi.fix_pathinfo=1
設置完整的路徑信息PATH_TRANSLATED的值為SCRIPT_FILENAME,並且設置PATH_INFO信息
Another Fix
security.limit_extensions = .php
[3] SCRIPT_NAME
Setting
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass 127.0.0.1:9000;
}
GET /index.php/<script>alert(1)</script>/index.php
SCRIPT_NAME = /index.php/<script>alert(1)</script>/index.php
[Fix]
1. $request_filename
Use $request_filename instead of $document_root$fastcgi_script_name.
2. cgi.fix_pathinfo=0 in php.ini
cgi.fix_pathinfo
3. try_files
location ~* \.php$ { try_files $uri =404; fastcgi_pass backend; # [...] }
4. Ensure that NGINX only passes specific PHP files for execution:
location ~* (file_a|file_b|file_c)\.php$ { fastcgi_pass backend; # [...] }
"try_files $uri" directive with "alias"