My last article was about the importance of web security in small applications and how to ensure security practices in those applications. So I thought to continue the conversation on the same topic.
This article is about various challenges with preventing unauthorized access. Let's untangle authentication, session management, and authorization in web applications.
Passwords are the most common authentication method. We are aware of the ways to make passwords more secure
such as
Do not use personal information such as the name of the child or pet
Do not use dictionary words or combinations of words such as the perfect person
Do not use the same passwords for multiple accounts
Tools like a password manager help to create and use a unique, single password for each account. If you are one of those users who doesn't trust software to store passwords, one way to reduce password exposure is to divide your accounts into trust levels and use different passwords for each. This level system separates sensitive sites, like banking sites, from unimportant sites, like a forum. Websites like https://haveibeenpwned.com can help you find out if your accounts are compromised.
The best way to store passwords securely is to use password hashing functions with a reasonable cost factor. The most popular hashing function is bcrypt. These are cryptographic functions that perform a certain amount of iterations to calculate the output. In practice, all recommended hashing functions should use a salt. The salt ensures the hash will differ, even if two users select the same password.
Bcrypt is a popular hashing function to generate hashcodes. There are other hashing functions like Scrypt, argon2, etc. For hashing small data like passwords, Bcrypt is one of the best. SHA-256 is better and faster for a large amount of data.
How to code hash using Bcrypt. The password is hard-coded, and the hash is output in the console in the below example. In real applications, passwords are not hard-coded and store the hash in a database. Below is the image of a hashcode of the password "myPaasword123#"
Below is the image of the hashcode with the salt of the above password
Preventing attacks
One of the threats against an application's authentication system is a brute force attack. In a brute force attack, the attacker tries to guess the password of the application's valid user. It seems like a hopeless effort, but the chances are one of the users of an application uses such a weak password.
The first strategy to prevent a brute force attack is to lock a user account after a certain number of authentication attempts. A second strategy is to slow down authentication attempts after a pair of failures. For example, after three attempts, the application waits for a second. After four attempts, it waits 3 seconds. After five attempts, it waits 10 seconds. As you can see, increasing the slowdown makes a brute-force attack infeasible. If a forgetful user needs a couple of tries, the 10-second wait will not have a significant impact.
The attacker also needs a valid username to authenticate. That is where the enumeration attack comes in. With an enumeration attack, the attacker can determine if a username exists in the application. If the application leaks such information, then it can be abused to compile a list of valid usernames. That list, in turn, enables the attacker to optimize his brute force attack.
The places where enumeration attack often happens are the login form, account recovery form, and registration form. On a login form, error messages shown in a login attempt with an existing account and a non-existing account can leak information about the existence of a username.
For example, as shown above, if an email like jane@example.com shows an error message like an unknown email address and if an email like john@example.com gives an error message like invalid email address, then the application is leaking information about the existence of a username john.
An account recovery form usually requests an email address. It immediately notifies the user when the email address does not exist(see example above).
When choosing a username or email address on a registration form, the application discloses if it already exists. The above image shows that this application is leaking the information that the username "john" exists.
To prevent an enumeration attack, refrain from giving the user immediate feedback about the existence of an email address. The user gets the same error message for existing and non-existing accounts in a login form. If an email address exists on a recovery form, send the recovery email, like before. If it does not exist, send a message that informs the user about the potential account recovery. Suggests that the user may have used a different email address to sign up. Alternatively, suggest that the user can always register a new account if desired. The application uses email addresses as a unique identifier on a registration form. In this case, implement a similar mechanism as for the recovery form. If the email address is unknown to the application, create a new account and send an email to the user. If the email address matches an existing account, send an email to remind the user of this account. The email should also include instructions on how to recover the password.
Multi-factor authentication
Password-based authentication has been in use for a long time. Password is something that the user knows. They are knowledge-based authentication factors. When the attacker learns the password, he/she/they can impersonate the user. So even with modern best practices, the password is a weak authentication system.
Let's explore what are the other forms of authentication. One form is possession-based authentication which uses the possession of a physical device such as a phone, or laptop for authentication purposes. Another form is user-inherent authentication which uses biometrics like fingerprint, retina scan, etc. The other one is behavior or context-based which includes properties like user behavior and user location. All these forms of authentication are weak in isolation. They are strong when used in combination with passwords. This technique is multi-factor authentication.
The most common one we have seen using is the password with a mobile verification code combined. Another one I have seen with big applications is allowing the use of a USB security key. Implementing this requires a lot of effort. I think some applications have delegated authentication to third-party services like sign-in with Google to reduce the cost of effort needed. Delegating such authentication depends on the use of OAuth2.0 or OpenID connect. Securely implementing them also has challenges, but as an application provider, delegating authentication to a third party makes security implementation easier.
In conclusion, we've explored the intricate world of authentication in-depth and we've only scratched the surface. The journey into the realm of secure web applications continues. Our next destination: Session Management. Given the depth of these topics, we've decided to split our exploration into multiple blogs to provide you with the most comprehensive understanding. So, stay tuned for the next blog where we dive headfirst into the crucial domain of Session Management, uncovering its intricacies and best practices, and then onto authorization. Your journey to mastering web security is just beginning. Until then, happy coding, and stay secure!
Update: Read session management in access control here: https://rafna.hashnode.dev/session-management-in-access-control-of-web-applications