Nginx – How to deny shell execution in all sub-directories

nginxSecurity

I want nginx to deny users who have folders inside /webroot/uploads

e.g.

/webroot/uploads/user1
/webroot/uploads/user2
/webroot/uploads/user1000

to execute any shell (php, pl, exe).

The shells are often hidden in jpg or gif files. like badfile.php.jpg

I also see malacious binary files being uploaded to the folder.

Here my preliminary rules:

location ~ /webroot/uploads/(.+)\.php$ {
 deny all;
}

location ~ /webroot/uploads/(.+)\.pl$ {
 deny all;
}

But I am not sure it is robust. So I appreciate your help.

Best Answer

If you want to absolutely ensure nothing executes in /webroot/uploads, or anywhere underneath, I would suggest blocking execution at the filesystem level. Create a filesystem for /webroot/uploads, and mount it with the 'noexec' option:

mount -t ext4 -o 'noexec,rw' /dev/<device-name> /webroot/uploads/

Note: If you're using a managed server, or otherwise don't have available storage to provision for a filesystem, you can mount this on to a loopback device:

Warning: Before running the following commands, back up /webroot/uploads and move the files to a temporary location.

  1. Return the next available loop device - will be one of /dev/loop[0-8]

    sudo losetup -f  
    
  2. Create an image to act as the filesystem - this creates a 1GB file in /opt

    sudo dd if=/dev/zero of=/opt/uploads_fs.img bs=1M count=1024  
    
  3. Configure the loopback device returned in the first command to use the new file

    losetup /dev/loop0 /opt/uploads_fs.img    
    
  4. Create a filesystem

    mkfs.ext4 -m 1 -v /dev/loop0  
    
  5. Mount /webroot/uploads on the new device with noexec set

    mount -t ext4 -o 'noexec,rw' /dev/loop0 /webroot/uploads/
    

At this point, restore your files to their previous locations. Even as the root user, you will not be able to execute files on that filesystem:

[root@localhost testfs]# ll myscript*   
-rwxrwxrwx. 1 root root 41 Jan 21 19:20 myscript.sh  
[root@localhost testfs]# ./myscript.sh  
-bash: ./myscript.sh: Permission denied  
[root@localhost testfs]#   
Related Topic