nginx: How To Block Exploits, SQL Injections, File Injections, Spam, User Agents, Etc.

This short article explains how you can block the most common exploits, SQL injections, file injections, spam and user agents used by hackers and bandwidth hoggers from your nginx vhosts with some simple configuration directives. This configuration is far from being complete, but it's a good starting point. You will have to watch your logs for attempted break-in attempts and then try to modify/complete the ruleset.

Modify Your Nginx Vhosts

The ruleset I use here has to be inserted in each nginx vhost (inside a server {} container) where you want to use it. Unfortunately, it can't be used globally because the set directive is not allowed inside the http {} container.

server {
[...]

    ## Block SQL injections
    set $block_sql_injections 0;
    if ($query_string ~ "union.*select.*\(") {
        set $block_sql_injections 1;
    }
    if ($query_string ~ "union.*all.*select.*") {
        set $block_sql_injections 1;
    }
    if ($query_string ~ "concat.*\(") {
        set $block_sql_injections 1;
    }
    if ($block_sql_injections = 1) {
        return 403;
    }

    ## Block file injections
    set $block_file_injections 0;
    if ($query_string ~ "[a-zA-Z0-9_]=http://") {
        set $block_file_injections 1;
    }
    if ($query_string ~ "[a-zA-Z0-9_]=(\.\.//?)+") {
        set $block_file_injections 1;
    }
    if ($query_string ~ "[a-zA-Z0-9_]=/([a-z0-9_.]//?)+") {
        set $block_file_injections 1;
    }
    if ($block_file_injections = 1) {
        return 403;
    }

    ## Block common exploits
    set $block_common_exploits 0;
    if ($query_string ~ "(<|%3C).*script.*(>|%3E)") {
        set $block_common_exploits 1;
    }
    if ($query_string ~ "GLOBALS(=|\[|\%[0-9A-Z]{0,2})") {
        set $block_common_exploits 1;
    }
    if ($query_string ~ "_REQUEST(=|\[|\%[0-9A-Z]{0,2})") {
        set $block_common_exploits 1;
    }
    if ($query_string ~ "proc/self/environ") {
        set $block_common_exploits 1;
    }
    if ($query_string ~ "mosConfig_[a-zA-Z_]{1,21}(=|\%3D)") {
        set $block_common_exploits 1;
    }
    if ($query_string ~ "base64_(en|de)code\(.*\)") {
        set $block_common_exploits 1;
    }
    if ($block_common_exploits = 1) {
        return 403;
    }

    ## Block spam
    set $block_spam 0;
    if ($query_string ~ "\b(ultram|unicauca|valium|viagra|vicodin|xanax|ypxaieo)\b") {
        set $block_spam 1;
    }
    if ($query_string ~ "\b(erections|hoodia|huronriveracres|impotence|levitra|libido)\b") {
        set $block_spam 1;
    }
    if ($query_string ~ "\b(ambien|blue\spill|cialis|cocaine|ejaculation|erectile)\b") {
        set $block_spam 1;
    }
    if ($query_string ~ "\b(lipitor|phentermin|pro[sz]ac|sandyauer|tramadol|troyhamby)\b") {
        set $block_spam 1;
    }
    if ($block_spam = 1) {
        return 403;
    }

    ## Block user agents
    set $block_user_agents 0;

    # Don't disable wget if you need it to run cron jobs!
    #if ($http_user_agent ~ "Wget") {
    #    set $block_user_agents 1;
    #}

    # Disable Akeeba Remote Control 2.5 and earlier
    if ($http_user_agent ~ "Indy Library") {
        set $block_user_agents 1;
    }

    # Common bandwidth hoggers and hacking tools.
    if ($http_user_agent ~ "libwww-perl") {
        set $block_user_agents 1;
    }
    if ($http_user_agent ~ "GetRight") {
        set $block_user_agents 1;
    }
    if ($http_user_agent ~ "GetWeb!") {
        set $block_user_agents 1;
    }
    if ($http_user_agent ~ "Go!Zilla") {
        set $block_user_agents 1;
    }
    if ($http_user_agent ~ "Download Demon") {
        set $block_user_agents 1;
    }
    if ($http_user_agent ~ "Go-Ahead-Got-It") {
        set $block_user_agents 1;
    }
    if ($http_user_agent ~ "TurnitinBot") {
        set $block_user_agents 1;
    }
    if ($http_user_agent ~ "GrabNet") {
        set $block_user_agents 1;
    }

    if ($block_user_agents = 1) {
        return 403;
    }
[...]
}

Whenever one of the rules matches a request, a 403 Forbidden error is returned to the client. I've commented out the wget rule here because this would also block cron jobs that use wget which is quite common among modern CMS applications. If your application doesn't use wget, you can uncomment that rule as well.

Don't forget to reload nginx:

service nginx reload

ISPConfig Nginx Servers

These rules can also be used in the Nginx Directives field in ISPConfig. Just paste the rules into the Nginx Directives field on the website options tab in ISPConfig, without the surrounding server { ... } block. The nginx reload is applied by ISPConfig automatically when you save the changes.

 

About The Author

Falko Timme is the owner of nginx WebhostingTimme Hosting (ultra-fast nginx web hosting). He is the lead maintainer of HowtoForge (since 2005) and one of the core developers of ISPConfig (since 2000). He has also contributed to the O'Reilly book "Linux System Administration".

Share this page:

Suggested articles

9 Comment(s)

Add comment

Comments

By: MrOwen

Great rulesets!

If I'm not mistaken, these rules can be added to a separate config file and then included for each server block (I feel nginx would allow this). Another thing; I've come across many resources regarding the use of conditional "ifs" in the nginx config and it seems the overwhelming majority of them strongly discourage the use of it citing a hit on performance (they suggest using try_files or something similar but, obviously, that isn't applicable here so perhaps these if statements are a "necessary evil" in terms of optimizing a config).

By: ViruSzZ

hey, those are really great tips for additionally securing my nginx server.

was wondering if there's anywhere online to read more deeply about all this options ?

thanks,

 - d

By: Anonymous

The article is a poor solution to the problem they are trying to tackle.  The better answer is to use naxsi, the application firewall for nginx.

 

By: Tomas

What is this line stopping exactly? As far as I can tell you're only blocking very specific query strings like ?foo=/b/ whereas ?foo=/b/ might be a completely legitimate request.

if ($query_string ~ "[a-zA-Z0-9_]=/([a-z0-9_.]//?)+")

I'm asking because I don't see the point of the slash-one-character-slash bit (/[a-z0-9_.]/), did you forget a + there or am I missing something?

The above regex will match /?foo=/b/ar/ but not /?foo=/etc/passwd

By: Aaron

I've been hit with a torrent of /? spam and have resorted to .htaccess to block it, but I find that it does block some legitimate queries. Like the code I've found below works, but it also blocks the previews on wordpress from working:

`<IfModule mod_rewrite.c>RewriteCond %{QUERY_STRING} ^[\-/A-Z0-9]+$ [NC]RewriteRule (.*) - [R=404]</IfModule>`

Any ideas on how to improve this?

Thanks!

By: Or

Return 444; is better.

https://httpstatuses.com/444

By: fbifido

Howdo i host multiple site on one IP, using ngix?

 

By: Thomas @VirtuBox

Can be optimized and configure without "if" :

https://gist.github.com/VirtuBox/5fedc39c30813f5373aa8ae9328a0ec3

By: Serra

I can do that in apache?