'Nginx disallowing execution of PHP in uploads directory with Magento
I'm having difficulties getting nginx to stop execution of PHP in an uploads directory on a magento install. I've tried many combinations of directives that should've sent a 503 or similar when *.php is matched in that directory, but still I'm able execute PHP in there. Of-course the code solution is to prevent .php files from being uploaded but I don't understand how to prevent the execution from an nginx perspective.
map $http_x_ssl_offloaded $fastcgi_https {
default off;
on on;
}
server {
listen 80;
server_name store.xxxx.com;
root /var/www/store.xxxx.com;
#charset koi8-r;
#access_log /var/log/nginx/store.xxxx.com-access.log main;
access_log /var/log/nginx/store.xxxx.com-access.log;
error_log /var/log/nginx/store.xxxx.com-error.log;
gzip on;
gzip_disable msie6;
gzip_static on;
gzip_comp_level 9;
gzip_proxied any;
gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript;
location / {
index index.html index.php;
try_files $uri $uri @handler;
expires 30d; ## Assume all files are cachable
}
## Location for media to prevent execution of php
location ^~ /media/ {}
## These locations would be hidden by .htaccess normally
location ^~ /app/ { deny all; }
location ^~ /includes/ { deny all; }
location ^~ /lib/ { deny all; }
location ^~ /media/downloadable/ { deny all; }
location ^~ /pkginfo/ { deny all; }
location ^~ /report/config.xml { deny all; }
location ^~ /var/ { deny all; }
location /var/export/ { ## Allow admins only to view export folder
auth_basic "Restricted"; ## Message shown in login window
auth_basic_user_file htpasswd; ## See /etc/nginx/htpassword
autoindex on;
}
location /. { ## Disable .htaccess and other hidden files
return 404;
}
location @handler { ## Magento uses a common front handler
rewrite / /index.php;
}
location ~ .php/ { ## Forward paths like /js/index.php/x.js to relevant handler
rewrite ^(.*.php)/ $1 last;
}
# Pass all PHP scripts to the PHP-FPM
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
if (!-f $document_root$fastcgi_script_name) {
return 404;
}
expires off; ## Do not cache dynamic content
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param MAGE_RUN_CODE en_us;
fastcgi_param MAGE_RUN_TYPE store;
fastcgi_param SSL_OFFLOADED $fastcgi_https;
fastcgi_param HTTPS $fastcgi_https;
fastcgi_read_timeout 6000;
}
location /api {
rewrite ^/api/rest /api.php?type=rest last;
rewrite ^/api/v2_soap /api.php?type=v2_soap last;
rewrite ^/api/soap /api.php?type=soap last;
}
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
# deny running scripts inside writable directories
location ~* /(images|cache|media|logs|tmp)/.*\.(php|pl|py|jsp|asp|sh|cgi)$ {
return 403;
error_page 403 /403_error.html;
}
# caching of files
location ~* \.(ico|pdf|flv)$ {
expires 1y;
}
location ~* \.(js|css|png|jpg|jpeg|gif|swf|xml|txt)$ {
expires 14d;
}
# redirect server error pages to the static page /40x.html
#
error_page 404 /404.html;
location = /40x.html {
}
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
location ~ /\.ht {
deny all;
}
}
Solution 1:[1]
The official docs say:
...regular expressions are checked in the order of their appearance in the configuration file. The search of regular expressions terminates on the first match, and the corresponding configuration is used.
Therefore your location for denying scripts should come before the location for executing scripts.
I am less certain here but I think the reason this doesn't work:
## Location for media to prevent execution of php
location ^~ /media/ {}
...is because it has no immediate effect and the compiler optimises it out completely.
Solution 2:[2]
Try to add to the line:
location ~ [^/]\.php(/|$) {
the following directive (change "your_directory" with the folder you need to forbid php file uploads for):
location ~* /your_directory/.*\.php$ {
return 503;
}
Solution 3:[3]
Try
location /media/ {
......
# Banned locations
location ~* (\.php$|\.phtml$|\.htaccess$|\.git) {
deny all;
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | clockworkgeek |
Solution 2 | Mageworx |
Solution 3 | MagePal Extensions |