Weak credential policy
Need
Enforcement of a strong password policy, covering password expiration, complexity requirements, and secure temporary password handling
Context
• Usage of Ruby for building dynamic and object-oriented applications
• Usage of aws-sdk-iam for managing AWS Identity and Access Management (IAM) resources
• Usage of Ruby 2.3+ as the required version for running the application
• Usage of bcrypt for password hashing and encryption
• Usage of Ruby 2.7 for developing Ruby applications
• Usage of Rails for building web applications
Description
1. Non compliant code
# --- Password Expiration ---
require 'aws-sdk-iam' # aws sdk gem for IAM
iam = Aws::IAM::Client.new(region: 'us-west-2')
# Create an IAM group
group = iam.create_group({group_name: 'MyGroovyGroup'})
...**Password Expiration:** In the above code, we are using AWS SDK for IAM to manage AWS IAM users, groups and password policies. First, we create an IAM client with the region 'us-west-2'. Then, we create an IAM group named 'MyGroovyGroup' and a user named 'MyGroovyUser'. We then add the user to the group. Next, we create a password policy with the following attributes: minimum_password_length: 8, require_symbols: true, require_numbers: true, require_uppercase_characters: true, require_lowercase_characters: true, allow_users_to_change_password: true, password_reuse_prevention: 3, hard_expiry: false. The vulnerability lies in the `hard_expiry: false` line. This line disables the password expiration flag. This means that the password for the IAM user 'MyGroovyUser' will not expire, which is a security risk. Good security practices suggest that credentials should be renewed in 90 day periods. Therefore, the `hard_expiry` flag should be set to `true` and the `max_password_age` should be set to 90. **Password strength:** The above code represents a model `User` in a Ruby on Rails application. The `has_secure_password` method is used to handle password hashing in the database. However, this method alone does not enforce any kind of password complexity or length requirements, which is a security vulnerability. This can lead to weak passwords being used by users, which are easier to crack and can lead to unauthorized access to user accounts. A weak credential policy can be exploited through brute force or dictionary attacks. In this code, there's no policy in place to ensure the password contains a minimum number of characters, upper and lower case letters, numbers, and special characters. This means a user could potentially have a password as simple as "password" or "1234", which are extremely easy to guess or crack. **Temporary passwords:** The vulnerable code above is a `reset_password` method in the `UsersController` class. The method is responsible for resetting user's passwords. However, the vulnerability lies in the fact that the new password is a hardcoded string 'password123' which is weak and does not follow any strong password policy. In this scenario, when a user requests for a password reset, the system assigns a weak, easily guessable password 'password123' to the user's account. This makes the user's account highly susceptible to brute force attacks as the attacker can easily guess the password. Moreover, the same temporary password is assigned to every user who requests a password reset, which means if an attacker compromises one account, they can potentially access any other account that has had its password reset. In addition, there is no mechanism in place to force the user to change this temporary password immediately after logging in, which means the user might continue using this weak password, further increasing the risk of their account being compromised.
2. Steps
• Enable password expiration in the AWS IAM policy and set the expiration period to 90 days.
• Update the code to reflect the changes in the IAM policy.
• Implement a password strength policy that enforces minimum requirements for passwords, such as minimum length, required character types (uppercase, lowercase, numbers, special characters), and any other relevant criteria.
• Update the User model to include validations for password strength based on the defined requirements.
• Use a password hashing algorithm that is considered secure, such as bcrypt, to store the passwords securely.
• Generate a random and secure temporary password instead of using a static or predictable one.
• Ensure that the temporary password is only valid for a limited period of time and expires after a certain duration.
• Encrypt the temporary password before storing it in the database to protect it from unauthorized access.
• Implement a secure password reset mechanism that requires additional verification steps, such as sending a verification email or using multi-factor authentication.
• Log all password reset activities for auditing purposes.
• Educate users about password strength and expiration requirements, and provide guidance on creating strong passwords.
• Implement a mechanism to enforce password changes periodically or when there is suspicion of compromise.
• Regularly review and update the password policy as needed to adapt to evolving security threats.
3. Secure code example
# --- Password Expiration ---
require 'aws-sdk-iam' # aws sdk gem for IAM
iam = Aws::IAM::Client.new(region: 'us-west-2')
# Create an IAM group
group = iam.create_group({group_name: 'MyGroovyGroup'})
...**Password Expiration:** The updated code now includes a password policy that enforces password expiration every 90 days. This is achieved by setting the `hard_expiry` flag to `true` and the `max_password_age` to `90`. The `hard_expiry` flag, when set to `true`, enables password expiration. The `max_password_age` parameter sets the maximum number of days that an IAM user's password is valid. When the specified number of days since IAM user's password was last changed is exceeded, the IAM user is no longer allowed to use the AWS Management Console, but they can still access AWS services through the AWS CLI or AWS API. This change ensures that the AWS IAM policy adheres to good security practices by requiring credentials to be renewed every 90 days. **Password strength:** The updated code includes a validation for the password attribute of the User model. This validation uses a regular expression to enforce the following password strength requirements: at least 8 characters long, at least one uppercase letter, at least one lowercase letter, at least one number, and at least one special character. The `has_secure_password` method is a built-in Rails method that includes password hashing using bcrypt, which is a secure password hashing algorithm. This method also automatically adds a presence validation for the password field. The validation error message provides clear guidance to users about the password strength requirements. This code update helps to mitigate the risk of weak passwords, which can be easily guessed or cracked by attackers. By enforcing a strong password policy, the system can better protect user accounts and sensitive data from unauthorized access. **Temporary passwords:** The updated code now includes a method `generate_temp_password` that generates a random, secure temporary password using the `SecureRandom.base64` method. This method generates a random string of the specified length, in this case 15 characters. The `tr` method is used to replace certain characters that might be confusing in a password ('+/=lIO0') with others ('pqrsxyz'). The temporary password is then assigned to the user's password field. The time at which the password reset was sent is also recorded in a `password_reset_sent_at` field. This can be used to implement a policy where the temporary password expires after a certain duration. After the user's password and `password_reset_sent_at` fields are updated, the changes are saved to the database using the `save!` method. Finally, a password reset email is sent to the user using a hypothetical `UserMailer.password_reset` method. This method would need to be implemented in your `UserMailer` class, and would send an email to the user with instructions on how to reset their password. This approach ensures that the temporary password is both secure and temporary, and that the user is notified of the password reset. It also provides a basis for implementing additional security measures, such as password encryption and expiration, multi-factor authentication, and activity logging.
References
• 035. Weak credential policy