I have a Django web app where people write comments and upvote/downvote others' comments. The webserver is gunicorn + nginx (reverse proxy). The db is postgresql. The db and web app reside in two different ubuntu-based machines.

Some malicious users have begun abusing the voting feature, giving themselves thousands of votes within a few mins (or downvoting others). My servers effectively get DDOSed when such a script is run. Some of these people also impersonate other users by stealing their cookies!

I want to detect this behavior early, at nginx level. I was thinking I'd install fail2ban and write a policy. A policy can then be if more than 10 votes originate from an IP within 15 secs, send that IP to jail (i.e. redirect to a jail url) for 30 mins.

Now in my access.log, a vote (up or down) creates the following: - - [14/Feb/2016:06:51:10 +0000] "POST /vote/ HTTP/1.1" 302 5 "http://example.com/?sorg_service_id_internal=373234912870626%3BAfq3$.

Being new to this, I need help with implementing my policy.Will it be failregex = ^ \vote\ in the .conf file's [Definition] and the following in jail.local:


enabled  = true
port     = http,https
filter   = nginx-votefraud
logpath  = /var/log/nginx/access.log
maxretry = 10
findtime = 15
bantime  = 3600
banurl   = /banned/

Is that it?

Note: Also of interest to me is how this can affect performance of the web app. Is implementing fail2ban relatively light in your experience or a substantial cost is incurred? Assume this is the only policy I implement. The discussion here seems to suggest it could be costly on the RAM?

  • 1
    because this is a config question, I'm migrating to SuperUser – schroeder Feb 18 '16 at 22:48
  • Sounds like you have more serious problems than just DoS if malicious users can do all that. – multithr3at3d Feb 19 '16 at 19:39
  • @korockinout13 we're investigating the XSS issue separately (feel free to suggest something off the top of your head), but as for vote fraud, I feel fail2ban can catch that at the webserver level and effectively make the behavior too punishing to do. Thus fail2ban is a critical part of the strategy. If you've seen my question, feel free to suggest an answer. – Hassan Baig Feb 19 '16 at 20:22

You should look at those two modules of nginx:

This helps you limiting the requests and/or the connections which prevents the hammering of your backend. Then I'd add a check if the user already voted for a specific post and deny a second vote if so.
You then can still check the log for 503 (Service Temporarily Unavailable) and use fail2ban to keep those out who trigger nginx limits (too often).

  • I didn't get the bit about 503 (Service Temporarily Unavailable). Can you clarify it with an example? – Hassan Baig Mar 3 '17 at 17:13
  • You set a limit with one of those modules. The limit is triggered. The requester gets an 503. This is also logged into the access.log. You can use this for the fail2ban to block the requesters IP when nginx detects the hammering. This way your backend is protected through nginx and nginx is protected by fail2ban which uses iptables (firewall, packet drop). – unNamed Mar 3 '17 at 17:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.