Monolune

Methods of protecting login pages

Login pages are sometimes frequented by bots trying password combinations in attempts to gain access to private information protected by login credentials. From my web server logs, I sometimes see automated attempts in submitting login credentials through my login pages. This article will sometimes reference potential implementations using NGINX, but the concepts should transfer cleanly if another web server is used (e.g. Apache HTTP Server).

1. Rate limiting

You can limit the rate at which your login pages can be accessed. Alternatively, you can limit the rate at which login credentials are submitted (e.g. by limiting login credentials POST requests). Rate limiting is effective in slowing down automated brute force attacks by bots that target your login pages in hopes of finding a valid login credential.

By default, NGINX comes with ngx_http_limit_req_module. It can be used to limit the amount of HTTP requests an IP address can make within a period of time. Rate limiting is simple to set up. The NGINX blog and the ngx_http_limit_req_module documentation provide clear and fairly comprehensive explanations of the set up process and implications.

2. Cookie access tokens

This sounds like additional complexity, but while rate limiting can be effective in reducing the amount of tries by bots, it does not prevent bots from accessing login pages and trying out combinations in the first place. Having cookie access tokens is a way of denying access to login pages.

This scheme involves the login page rejecting any HTTP request that does not have a specified cookie (we will call this cookie the 'cookie token'). One way of implementing this is to have another web page that is responsible for handing out cookie tokens. For example, if we have 'https://www.example.com/login' as our login page, we can have 'https://www.example.com/get-cookie-token' as the page where cookie tokens are handed out. A normal request to the login page will result in a 401, 403, or 444 error (you decide on the appropriate error code), but a user who first accesses 'https://www.example.com/get-cookie-token' followed by the login page will be able to access the login page.

Such a scheme has a good chance of misleading casual bots about the existence of login pages.

If extra 'security' is desired, the page where cookie tokens are handed out can be password protected, possibly using HTTP Basic Authentication. NGINX has a module for HTTP Basic Authentication.

You may have noticed that the problem with this scheme is that if the cookie token page requires login credentials, then the target for bots has shifted from the login page to the cookie token page. In addition, if the cookie token page requires login credentials, we would need two sets of credentials to login when previously, we needed only one.

The value of this scheme comes from its scalability when used under a single domain name. If one has 'https://www.example.com/login', 'https://mail.example.com/login', and 'https://logging.example.com/login', all of those pages can be hidden from bots (and malicious users) by requiring a cookie token issued by, say, 'https://token.example.com/issue-token'. If an attack on the cookie token page is a concern, rate limiting can be used. One can assume that an attack the cookie token page takes up less resources than an attack on the real login page, because a typical login page makes calls to a backend database, while the page issuing cookie tokens uses only HTTP Basic Authentication. This is an advantage of the cookie access token method if resource consumption by bots is a concern.

3. Login page knocking

This is the login page equivalent to SSH port knocking. For example, if one wants to access the login page, one has to first access the 'Contact Us' page, the 'About Us' page, and the 'Search' page, all in the right order. Accessing the specified pages in the correct order is the 'knocking' part of this scheme that will subsequently allow the user (i.e. IP address) to access the real login page. If the 'knocking' is wrong, the login page will not be shown.

NGINX does not currently have built-in modules for this scheme. There exists third-party modules that facilitate this scheme. The modules vary greatly in effectiveness (some have basic issues) and code maintenance (some are abandoned by their authors), so I will not discuss these third-party NGINX modules here.

Conclusion

I often feel uncomfortable when my login pages are exposed to the public. In practice, I implement rate limiting and selectively implement the cookie access method. For now, the page knocking method is just a curiosity. I do not think it is worth the set up and maintenance effort, and I do not think it is convenient.

If you have to choose one method only, go with rate limiting. It is simple to set up and maintain, and does what it is supposed to do.