In today’s digital age, where information flows seamlessly across the virtual realm, the importance of secure coding has never been more critical. Applications and systems are continually under the watchful eyes of both benevolent users and malicious actors. The first line of defence in this ever-evolving battleground is robust authentication.
This section provides 13 essential tips for software engineers to integrate into their applications’ authentication processes. These recommendations aim to strengthen your applications by enhancing security measures against unauthorized access, simultaneously cultivating trust among your user base, and ensuring the protection of sensitive data.
1. Utilize secure, unique, and case-insensitive usernames
Let’s say you are developing a web application that necessitates users to create accounts using their chosen usernames. It’s not uncommon for multiple users to desire the same username, differing only in letter casing, like ‘HappyBunny,’ ‘happyBunny,’ and ‘HAPPYBUNNY.’ Storing these variations as separate entities in your database can potentially lead to login issues down the line.
To address this challenge, consider standardizing all usernames to a common format, typically lowercase, to eliminate case-related discrepancies. By storing a single, standardized value, such as ‘happybunny,’ the potential for confusion is drastically reduced.
To implement this, validate the chosen username’s availability before finalizing new account credentials. This process ensures that the first user to select the username ‘happybunny’ proceeds successfully, while subsequent users receive an error message indicating that the username is already in use. This approach guarantees the uniqueness of usernames within your database.
For applications with stringent security requirements, an alternative approach is to have the system generate a username on the user’s behalf. This practice is particularly prevalent in corporate systems, where employees are assigned predetermined usernames.
2. Avoid using internal accounts for front-end logins
Establish a clear distinction between user accounts designed for external or front-end access and those intended for internal purposes. Under no circumstances should internal accounts be employed for external access.
Maintain a separate set of credentials exclusively for internal use. These credentials must be handled with the utmost confidentiality and shared only with authorized personnel.
Examples of such sensitive accounts include administrator accounts, root accounts, database administrator (DBA) accounts, vendor accounts, and cloud service provider (CSP) accounts. These accounts should never be utilized to log into any front-end interface.
Recognizing their exclusive internal role, it is crucial not to employ the same authentication method for Demilitarized Zone (DMZ) and public access. Instead, employ a distinct set of credentials and separate login procedures when accessing these interfaces.
By adhering to these best practices, the security and integrity of sensitive internal accounts can be effectively maintained, ensuring they remain protected from unauthorized external access.
3. Enforce a minimum password length of 8 characters
Weak passwords are vulnerable to brute force attacks, making it essential to adhere to best practices regarding password length:
Mandatory minimum length: Implement a strict policy mandating a minimum password length of 8 or more characters. This serves as an initial defense against simple password breaches.
Length consideration: Do not restrict or truncate passwords that exceed a certain length limit. Allowing longer passwords enhances security by enabling users to create complex and harder-to-guess passphrases.
Inclusive character set: Enable the use of all characters, including Unicode characters and whitespace. This broadens the possibilities for creating strong and diverse passwords.
Credential rotation: In the event of a password leak or compromised credentials, enforce mandatory credential rotation. This practice bolsters security by rendering any leaked credentials obsolete.
Password strength feedback: Provide users with password strength feedback to assist them in crafting more secure passwords. This feedback mechanism can also prevent the use of passwords that have been compromised in the past or those recognized as common and easily guessable.
4. Implement password reset through a secure side-channel
It’s a common occurrence for individuals to forget their passwords. Therefore, it’s crucial to have a reliable password recovery process in place to enable users to regain access to their accounts in such cases.
However, password recovery mechanisms can introduce vulnerabilities, as attackers may exploit them through techniques like user enumeration attacks. To enhance security, provide instructions for users to reset their passwords using a separate communication channel distinct from the primary one used to access the application or service. This security measure minimizes the risk of unauthorized account access.
Side-channels refer to alternative communication methods that are not directly linked to the primary application interface. For instance, if users primarily access your application through a web interface, a side-channel could involve a phone number or an email address associated with their account, which could be used for password reset purposes.
The rationale behind utilizing a side-channel for password reset is to ensure the security and integrity of the password reset process, making it less susceptible to exploitation by attackers. By employing a distinct channel, you can prevent scenarios where an attacker who gains unauthorized access to a user’s main account interface can manipulate the password reset process.
For example, if an attacker gains access to a user’s email account, they might attempt to reset passwords for other accounts linked to that email.
By implementing a side-channel, even if the attacker compromises the user’s primary communication channel (e.g., email), they would still require access to the secondary side-channel (e.g., phone number) to complete the password reset procedure.
Leveraging a side-channel for password reset introduces an additional layer of security, making it substantially more challenging for unauthorized individuals to take control of an account.
5. Utilize secure URL tokens for one-time use
In certain scenarios, it becomes necessary to send a URL with additional actions to unauthenticated users. These URLs are accompanied by one-time tokens, which serve to identify the purpose of the request.
Examples of such scenarios include resetting a forgotten password or sending an invitation to join a group.
For instance, you may encounter a URL like this:
http://www.mydomain.com/forgot-password?one_time_token=some-xyz-token
To bolster the security of URL tokens, especially when implementing password reset functionality, adhere to the following guidelines:
Use cryptographically secure token generation: Employ a cryptographically secure algorithm to generate tokens. Utilize a secure random number generator with a well-chosen seed to create tokens. Ensure that these tokens are of sufficient length and characterized by unpredictability.
Secure server-side storage: Store these tokens securely on the server-side, avoiding plaintext storage to prevent unauthorized access. Implement robust measures to safeguard the tokens from potential breaches.
Enforce one-time use: Each token should only be valid for a single use. Implement an expiration mechanism to render tokens invalid after a predefined duration, even if they remain unused.
Rigorous token verification: When a user initiates a password reset, they often receive a token (a unique code or link) as part of the reset process. It is imperative to rigorously verify the legitimacy of this token to prevent unauthorized access. Verification involves confirming that the token matches what was originally sent to the user.
By adhering to these practices, the security and integrity of URL tokens are enhanced, reducing the risk of unauthorized access and potential misuse.
6. Secure password storage using cryptographic methods
The security of passwords is of utmost importance, and it’s essential to store them using a cryptographic system that effectively prevents unauthorized access, even in the event of a compromise of your application.
When it comes to storing passwords, adherence to specific guidelines is crucial:
Utilize a secure hashing algorithm, such as PBKDF2: This should be the default choice unless there is a compelling reason to opt for an alternative method. Bcrypt is a viable alternative, provided you choose a reasonable work factor to determine the number of iterations in the hashing process for each password.
Implement salting: During the hashing process, append a unique string (known as a “salt”) to each password. Most contemporary algorithms inherently incorporate this feature to enhance security.
Consider adding a ‘pepper’ for extra security: Similar to salt, a “pepper” introduces an additional layer of security. However, it differs in that it is shared across all stored passwords, adding an extra element of protection.
By following these practices, you can ensure the security and integrity of your password storage system, mitigating the risk of unauthorized access and enhancing overall security.
7. Implement secure password hash comparison
Always compare user-created password hashes to the stored password hash using the comparison function provided by the programming language or framework. In cases where the built-in comparison function is unavailable, safeguard your comparison function against common attacks with the following measures:
Explicitly set variable types: Clearly specify whether variables are integers, strings, or Booleans for both the stored variable and the user-supplied input. This ensures that they are compared as the same type, guarding against certain denial-of-service (DOS) attacks.
Utilize a constant-time algorithm for information retrieval: Implement an algorithm that consistently requires a fixed amount of time to return information. This mitigates the risk of timing attacks.
By following these practices, you enhance the security of your password hash comparison process, reducing vulnerabilities and protecting against potential attacks.
8. Use TLS for secure password transmission
Ensure the use of robust transport protocols, such as TLS (Transport Layer Security), with a preference for TLS 1.2 or higher, when accessing both the login page and authenticated data. Neglecting to employ strong transport protocols for the login landing page can render it vulnerable to attackers who may manipulate data and access user credentials.
Likewise, when dealing with authenticated pages, always guarantee secure transmission. Failure to implement TLS 1.2 or an equivalent secure transport mechanism for authenticated pages may expose session IDs to potential interception by attackers, consequently compromising the security of user sessions.
9. Implement re-authentication for accessing sensitive features
Whenever a user intends to update critical information, such as their password or email address, or when making significant changes like modifying their shipping address, it is imperative to mandate the user to re-authenticate their account. This additional layer of security ensures the verification of the user’s identity before granting access to these pivotal functions.
Failure to require re-authentication exposes the system to an elevated risk of attackers exploiting vulnerabilities such as CSRF (Cross-Site Request Forgery) or XSS (Cross-Site Scripting) attacks to execute unauthorized transactions.
Furthermore, attackers might gain temporary access to the user’s browser session, potentially leading to session ID theft and session hijacking, presenting a significant security threat.
10. Enforce transaction authentication for any in-app purchase
Transaction authentication, also known as transaction authorization, is a way of preventing fraud by making sure only authorized users are performing sensitive operations, like a wire transfer of funds. Another example of transaction authentication is when an email contains a link with a token to unlock a user account.
Some functional guidelines for transaction authentication are to allow the user to identify and acknowledge transactions of significant data. Changing the authorization token should require using the current token, and changing the authorization method should require using the current method.
It should be easy for users to distinguish between the authentication process and the transaction authentication process. As a reminder, make sure that you use unique credentials for each transaction.
Non-functional guidelines include a recommendation that all transaction authorization should be performed and enforced on the server-side.
Similarly, on the server-side, the method of authorization should be enforced and transaction verification data should be generated. The application should prevent brute-forcing of authorization credentials by restarting the process after multiple failed attempts.
11. Utilize generic authentication responses for application errors
Error messages should strike a balance between being generic and actionable. Provide a message that addresses the issue without disclosing sensitive information such as usernames, passwords, or system statistics.
Instead of detailed error messages, consider directing users to a support page or contact for assistance.
Here are examples of secure generic responses compared to overly specific responses. The specific responses, while informative, risk revealing too much information to potential malicious users, whereas the generic responses offer the necessary information without compromising security:
Scenario: User experiences a login error
Generic response: “Sorry, there was an issue with your login. Please double-check your credentials and try again. If the problem persists, contact our support team for assistance.”
Overly specific response: “The login error occurred because your provided username, ‘user123’, does not match any records in our MySQL database. The issue might be related to a password hash mismatch. Our database is hosted on AWS RDS in the us-east-1 region. We are currently investigating the issue and will get back to you once we’ve resolved it.”
Scenario: User encounters an error while using a web application
Generic response: “We apologize for the inconvenience you’re experiencing. Our team is aware of the issue and is actively working on resolving it. Please try again later.”
Overly specific response: “You encountered a 404 error because the requested resource, ‘example.com/page’, could not be found on our server. This issue occurred due to a misconfiguration in our NGINX web server, which is running on version 2.3.6. We are currently troubleshooting the issue, and the expected resolution time is within the next 2 hours.”
Scenario: User encounters a timeout error
Generic response: “It seems like you’ve encountered a timeout error. This could be due to high server load or network issues. Please try your request again in a few minutes.”
Overly specific response: “You received a timeout error (HTTP status code 504) because our load balancer, running on an AWS EC2 instance with the ID i-12345678, failed to establish a connection with the backend server. This issue occurred at 14:37 UTC and lasted for approximately 5 minutes due to increased traffic caused by a sudden spike in user activity.”
12. Implement an application delay to thwart time-based attacks
In some instances, the intricacies of an application’s business logic can inadvertently create variations in processing times. An attacker with knowledge of these timing discrepancies may attempt time-based attacks. Let’s delve into this through the lens of a login feature.
In a typical scenario, an error is generated if the user doesn’t exist. However, if the user does exist but enters an incorrect password, the application may still produce an error but with a slightly extended processing time. This increased processing time could arise from tasks such as searching for the user in the database under specific loads or computing the password hash for comparison.
Consequently, an attacker can deduce the validity of a username based on the response time: a faster error suggests that the username doesn’t exist, while a delayed error implies that the username is valid. This discrepancy in response times provides valuable insights to the attacker.
To counter this threat, consider introducing a variable delay within your application to ensure that error responses consistently align with anticipated timing. This approach mitigates the risk of attackers gleaning insights into the application’s logic via timing analysis.
In cases where the concern for multiple failed login attempts is substantial, you may opt for additional security measures such as implementing CAPTCHA challenges.
13. Implement multi-factor authentication (MFA)
MFA substantially elevates security by necessitating users to provide two or more authentication factors, rendering it significantly more challenging for attackers to gain unauthorized access. It serves as a robust defense against common threats like password attacks and phishing, effectively mitigating the risk of data breaches and financial fraud. Beyond its security benefits, MFA also aligns with regulatory and industry compliance requirements, ensuring organizations adhere to necessary standards and avert potential legal consequences.
Moreover, it fosters a culture of heightened security awareness among users, reinforcing the critical importance of safeguarding accounts and sensitive data.
As the landscape of cybersecurity threats continues to evolve, MFA remains a versatile defense mechanism that adapts to new challenges, offering a vital layer of protection for systems, applications, and confidential information.
Despite the minor inconvenience of an additional step during login, MFA strikes a necessary balance between security and user convenience. Many MFA methods are user-friendly and readily accessible, such as mobile apps or SMS codes.
The manifold benefits of MFA, including reinforced protection against unauthorized access and data breaches, establish it as an indispensable tool in the modern cybersecurity landscape. Organizations and individuals should prioritize the adoption of MFA to bolster their overall security posture and diminish the risk of falling prey to cyberattacks.
Originally posted on: https://techleadsg.medium.com/secure-coding-for-authentication-75bcbe2d7ea
Subscribe to my newsletter at: https://softwareengineerplaybook.substack.com/
Read the full series in Secure Coding for Software Engineers.
Available on :
- Amazon Kindle: https://a.co/d/0BUnM9y
- Paperback: https://amzn.to/3PyFMwd
Top comments (0)