I have protected a web folder with Nginx's Auth_Basic module. The problem is, we can try several passwords until it works (brute force attacks). Is there a way to limit the number of failed re-tries?
I have protected a web folder with Nginx's Auth_Basic module. The problem is, we can try several passwords until it works (brute force attacks). Is there a way to limit the number of failed re-tries?
As far as I know, Auth Basic module doesn't support this feature, but you can do this by using Fail2ban.
Testing with a non-existent user, you will see something like belows in the error log:
2012/08/25 10:07:01 [error] 5866#0: *1 no user/password was provided for basic authentication, client: 127.0.0.1, server: localhost, request: "GET /pma HTTP/1.1", host: "localhost:81" 2012/08/25 10:07:04 [error] 5866#0: *1 user "ajfkla" was not found in "/etc/nginx/htpasswd", client: 127.0.0.1, server: localhost, request: "GET /pma HTTP/1.1", host: "localhost:81"
Then create necessary filter:
/etc/fail2ban/filter.d/nginx-auth.conf
/etc/fail2ban/jail.conf
Testing Fail2Ban rules:
fail2ban-regex /var/log/nginx/localhost.error_log /etc/fail2ban/filter.d/nginx-auth.conf
PS: Since Fail2ban fetches log files to ban, make sure
logpath
matches with your configuration.I'm amazed no on else has given this solution/workaround.
Nginx basic-auth and
htpasswd
support bcrypt password encryption with an optional cost variable. Bcrypt is designed to be slow, thus providing a hard limit on how fast you can attempt different passwords.When creating your basic auth username/password use
With a cost of 12 your server will likely not be able to try passwords more than a few times a second, increase that to say 14 and you'll probably be looking at around 1s per password attempt.
With that configured any reasonable password will be immune to brute force attack even if the attacker tried passwords continuously for years.
E.g. at 10 password attempts per second brute force attack on an 8 character alphanumeric password would take 692,351 years:
62**8 / (10*3600*24*365)
.This is much easier to configure and more fool-proof than setting up "intelligent" request limitting.
I don't believe nginx has any internal facility to do this. The documentation page doesn't suggest it's possible.
You can use Fail2Ban to block IP addresses that have repeated failed login attempts.
The Fail2Ban wiki has some nginx-specific patterns.
Fail2Ban should be available as a package on most of the big distros.
Nginx-HTTP-Auth-Digest module can replace the basic auth module with many additional feature suck as retry and timeout. Additional documentation is available here
The only downside is that this probably require rebuilding nginx
This can be acomplished with a combination of NGINX basic auth and rate limiting.
This snippet was extracted from my working config, but the snippet itself wasn't tested.
The basic concept is that you create a cookie that allows bypassing the rate limit then set the cookie once someone successfully authenticates. This way someone is rate-limited until they login at which point they can perform as many requests as they want.
The major downside to this approach is that the cookie is static, once someone is logged in on any account they can use the token to brute force other accounts. This is not a major issue if your users are trusted not to brute force the password of other users. However I don't think you can do better than this in NGINX's config. Ideally the cookie would be
hash("$remote_user-SomeRandomBytes")
so that the token is bound to the user that successfully logged in.Just to chime in my own solution to this problem: It is based on an other (popular) answer, similar to your problem. Here is the configuration:
It allows you to directly utilize the rate limiting feature of NGINX, without requiring the client to store e.g. cookies. Please note the comments in the configuration itself, as (due to the different NGINX phases) some statements may mess up the rate limits.