nginx - deny all *.php requests except index.php for security reasons
You can achieve this in a number of ways.
Integrating quite directly with what you have in your config file, you may wish to simply include a section such as the following;
location ~ \.php$ {
try_files index.php @error;
fastcgi_pass ...;
fastcgi_param SCRIPT_FILENAME /path/to$fastcgi_script_name;
...
}
location @error {
[config of however you want to handle errors]
}
Which will check for the existence of the requested file before allowing its access/execution.
Further to the above however, I would actually personally recommend using fail2ban which will provide you more comprehensive security if configured correctly; you can configure it to monitor your access logs in real-time and ban IPs from accessing your server(s) by automatically creating new iptables rules on-the-fly, with ban times which you specify.
Personally I have my servers configured to use fail2ban with nginx as per this article (or at least based upon that - you may alter it as you wish).
Related videos on Youtube
Sergey Serov
Programmer, Social Anthropologist. Languages: PHP, Python, JavaScript. Databases: MySQL, MariaDB. Linux: CentOS, Fedora, Ubuntu. Front-end: HTML, CSS. CMS and Frameworks: Drupal, jQuery. Version Control: git. My modules on drupal.org: https://drupal.org/project/popup_announcement https://drupal.org/project/google_recaptcha https://www.drupal.org/project/editor_email_link Personal site: www.sergey-serov.ru
Updated on September 18, 2022Comments
-
Sergey Serov over 1 year
os: CentOS 7
nginx: 1.6.2
httpd: apache 2.4.6
cms: Drupal 7After my server was compromised I removed all from server, reinstalled OS and soft, and restored data from backup. Now I configure all services in maximum security style.
After detail researching access logs - I decided to deny any requests for php files except index.php which is in the site documents root for improving security.
Nginx access log contents a lot of records like:
azenv2.php az.php
and
/*/wp-login.php /administrator/index.php /MyAdmin/index.php
First category - backdoors (and one of them hacked my sites, somebody send huge portion of spam from my server).
Second - somebody want to find popular cms and utilities and try some login@password, like admin@123456
My reasons to block both categories by nginx through deny requests to php files are:
Even if somebody will upload php-shell - it will be impossible to use it.
All these requests are 'not good' a priory - and to refuse them by nginx will protect drupal(httpd+php+mysql) to work and spent power.
My current config for one virtual host:
server { listen <server-ip>; server_name <site-name>; location ~* /sites/default/files/styles/ { try_files $uri @imagestyles; } location @imagestyles { proxy_pass http://127.0.0.1:<port>; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; access_log off; } location ~* \.(jpg|jpeg|gif|png|ico|css|bmp|swf|js|pdf|zip|rar|mp3|flv|doc|xls)$ { root <site-documents-root>; access_log off; } location ~ (^|/)\. { deny all; } location / { proxy_pass http://127.0.0.1:<port>; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; access_log <path-to-log-folder>/nginx_access.log main; } }
nginx.conf - was not changed after installation.
UPDATE
Finally I create this config for deny:location ~ \.php$ { access_log /path/to/log/nginx_deny.log name_log; deny all; }
and this config for proxy:
location =/index.php { proxy_pass http://127.0.0.1:<port>; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location =/cron.php { proxy_pass http://127.0.0.1:<port>; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location / { proxy_pass http://127.0.0.1:<port>; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }
1). So full information about attacks attempts is collects in log.
2). Server not make additional work for bad requests.
3). Drupal cron may work.-
Deer Hunter over 9 yearsA probably superfluous question: have you read the canonical serverfault.com/questions/218005/…
-
Sergey Serov over 9 yearsI had read a lot of about security during last two weeks :) I have no problems with fact of compromised - all actions already done - new os, soft, complex clean sites files. Now - I need to protect by maximum new server. ssh, selinux, httpd, php seems secure. Strongly nginx configurations can improve security.
-
BE77Y over 9 years@Peter unfortunately that would result in the denial of the request to index.php also, as the
location ~\.php$ { deny all }
directive would also matchindex.php
-
AD7six over 9 yearsWhat exactly does
which is in the site documents root for improving security
mean? Where was it before? There's also no php handling at all in the above config - so not very clear. -
Sergey Serov over 9 yearsAD7six, index.php always in the site root as by default. I want to refuse requests to use backdors (if they will appear in future) and deny spam traffic. I added some more information to the main description.
-
BE77Y over 9 yearsOf course not, but that is neither what was requested by OP nor what I detailed in my response. It is however a point worth noting - known vulnerabilities in packages should be tracked and software updated accordingly.
-
BE77Y over 9 yearsAlright, it would seem that
try_files
requires at least two arguments then - I would suggest that you set up a second argument to point to an error location if you wish (answer updated to reflect this change above)