Many Facets, One Goal
A common trope in cybersecurity is “don’t roll your own auth.” There’s a reason for this: implementing authentication is deceptively difficult. Many of the requirements for authentication are overlooked. Some of the features that modern authentication requires include:
- Rate limiting on the login form to prevent brute-force attacks
- Multi-factor authentication
- A method of resetting forgotten passwords
- Password storage and hashing
- Session management
A minor mishap in any of these features is likely to result in a critical account takeover vulnerability, which is why it’s important to follow authentication best practices. More on that later.
Multi-factor Authentication (MFA)
In 2024, MFA is seen as an essential part of the authentication process. MFA requires users to provide two or more unique identifiers to prevent unauthorized access. These identifiers include:
- Something the user knows: An account’s username and password, personal identification number (PIN), and correct answers to security questions are all examples of factors a user knows.
- Something the user has: Unique access codes that are delivered to a user’s device, either via an authenticator app or via contact methods such as the phone number or email address associated with the registered account.
- Something the user is: Biometric scanners such as facial recognition, voice recognition, fingerprint, or eye scanning technology.
Unfortunately, even when MFA is implemented, weak implementations can be bypassed. One relatively common example of this is when valid credentials grant a session token before MFA is verified, which is what happened in the real example below.
An Example of an MFA Bypass Vulnerability
On January 14, 2024, security researcher akhan8041 submitted a vulnerability report to the Drugs.com vulnerability disclosure program (VDP).
After submitting valid account credentials to
https://drugs.com/account/login, the user receives a one-time password to their registered email address. The user is meant to enter the one-time password into the MFA form to gain access to their account; however, due to a lack of verification, users were able to bypass MFA entirely and sustain a valid user session.
As this web application provides an interface to sensitive healthcare information, the finding was rated as critical in severity.
Steps to Reproduce
- Valid user credentials were submitted via the login form on /account/login.
- On the subsequent page, /account/verify-access/?referrer=%2F, users are presented with the message: “We sent a security code to [account email address]. Enter the 6-digit code below.”
- However, at this point, the application server had already issued all the required cookies for an active user session.
- By simply deleting the bb_refresh cookie and reloading the page, the MFA mechanism could be circumvented and a user could proceed with normal authenticated user activity.
Protecting Against MFA Attacks
MFA implementations can be vulnerable in many ways. Below are some of the main ones, along with how to prevent them.
Brute-forcible MFA Codes
Attackers might attempt brute-force attacks on OTPs or on recovery codes, especially if these codes are weak or have predictable patterns. Attackers may also attempt brute-forcing by guessing or automating input on authentication endpoints.
To mitigate this, implement rate limiting and lockouts, and reduce the lifespan of OTPs. Make sure that OTPs can only be used once, and that no more than one OTP can be active at the same time.
OTP Exposure
In some cases the correct OTP code is able to be retrieved by the attacker before they need to input it. Some examples of this are:
- The OTP code being exposed in accessible HTML or JavaScript on the entry page
- The OTP code being logged somewhere in plaintext
- When they’re sent via insecure channels (which can include SMS!)
Ensure that the code is never printed in the application. Avoid SMS-based OTPs where possible in favor of more secure methods, like app-based authentication or hardware tokens. Ensure OTPs are encrypted both in transit and at rest. Enforce app logging policies that mask OTPs in logs to prevent accidental exposure.
Improper Session Management
In the example above, a valid session token was sent to the user before the MFA code was validated. The user was only stopped from being authenticated by the existence of a client-side cookie (which could easily be removed by an attacker). This is an example of improper session management.
Session tokens should only be prescribed after the full authentication process has taken place and been validated on the server side.
With more evaluations spanning a broad range of both knowledge and techniques, through the power of human-powered security testing, you can ensure your authentication mechanisms are hardened.
11 Authentication Best Practices
There are also a number of best practices when it comes to authentication. Let’s take a look at some of the more important ones.
1. Rate-limiting for Brute-force Prevention
In the absence of rate limiting, brute-force attacks become feasible:
- Set limits on the number of login attempts within a certain period.
- Implement CAPTCHAs to counter credential stuffing attacks.
2. Enforcing Strong Password Policies
Define password policies that enforce stronger security:
- Require complex passwords that include a mix of letters, numbers, and special characters.
- Enforce a minimum length of the passwords, and enforce the maximum length to be at least 64 characters to allow passphrases.
- Refuse dictionary words or commonly used phrases, unless they’re used properly.
- Refuse identifiers such as the username, name, or email address in the password.
- Prevent the reuse of old passwords.
- Passwords should be rotated in the event of a breach.
- Block previously breached passwords. Services like Pwned Passwords can be used for this purpose.
3. Secure Handling of Credentials
Attention must be paid to the submission, storage, recovery, and modification of credentials:
- Use encrypted connections via Transport Layer Security (TLS).
- Hash and salt passwords with secure cryptographic algorithms such as Argon2id in the database.
- Consider using a pepper in addition to salting.
- Require users to re-authenticate before changing their passwords..
- Use Cross-Site Request Forgery (CSRF) tokens.
4. Implement Session Timeouts
Implementing session timeouts helps to prevent unauthorized access from unattended devices. This is especially important for highly sensitive applications such as banking apps.
5. Error Message Management
Error messages should be carefully handled to avoid giving attackers clues:
- Disable verbose error messages.
- Avoid indicating if a username exists to prevent account enumeration.
6. Implement System Monitoring
Despite secure authentication practices, breaches can occur. Log and monitor all authentication functions, including failed login attempts, password failures, and account lockouts. Review these logs regularly to detect and respond to potential attacks.
7. Don’t Roll Your Own Authentication
Creating your own authentication system might seem manageable, but it is rarely advisable. Authentication is complex, and subtle security flaws can make your system vulnerable to attacks. Leveraging established and tested libraries or services ensures that security vulnerabilities are minimized by using widely vetted, regularly updated solutions. Custom implementations often lack the scrutiny and resilience needed to defend against sophisticated attacks effectively.
8. Implement Multi-factor Authentication
MFA adds an extra layer of security by requiring more than one verification method:
- Combine something the user knows (password) with something they have (a device) or something they are (biometric data).
- Implement MFA for sensitive actions, like accessing critical data or making significant account changes.
- Require MFA for administrative or high-privileged users.
9. Secure Account Recovery Processes
Account recovery mechanisms are a common target for attackers:
- Avoid using easily guessed recovery questions and favor multi-factor verification for password resets.
- Use email or SMS verification codes for recovery, but also consider app-based authenticators for added security.
- Implement account lockout mechanisms to prevent brute-force attacks on password recovery.
- Monitor account recovery requests for unusual activity.
10. Monitor for Suspicious Login Behavior
Track and analyze login patterns to detect unusual activity:
- Implement IP-based monitoring to identify login attempts from suspicious locations.
- Monitor for abnormal login times or rapid attempts across different accounts.
- Use machine learning or rule-based systems to flag potentially malicious behavior.
11. Log and Audit Authentication Events
Logging helps to track authentication-related activity for accountability and threat detection:
- Log login attempts, both successful and failed, to identify potential brute force attacks.
- Retain logs securely for audit purposes and set up alerts for suspicious activities.
- Regularly review access logs for any anomalies.
Conclusion
Multi-factor authentication, though essential, is only as secure as its implementation. As we’ve explored, authentication vulnerabilities can stem from simple oversights, like improper session management, to more complex issues, such as brute-forceable MFA codes and OTP exposure.
Securing authentication requires strong session handling, rate limiting, and robust recovery processes. It’s essential to avoid “rolling your own auth” and instead rely on proven, vetted solutions whenever possible. Human-powered security testing, as exemplified by platforms like HackerOne, provides valuable insights into the vulnerabilities within authentication logic, helping organizations stay ahead of potential exploits.