Weak credential policy - Password Expiration
Need
Implementation of a strong credential policy with password expiration
Context
- Usage of Go 1.16 for developing high-performance and efficient applications
- Usage of AWS SDK for Go to interact with AWS services
- Usage of AWS SDK Go's session package for managing AWS sessions
- Usage of AWS IAM service for managing access to AWS resources
- Usage of gin-gonic/gin for building web applications in Go
- Usage of net/http for creating HTTP servers in a Node.js application
Description
Non compliant code
package main
import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/iam"
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
r.GET("/awsPolicy", func(c *gin.Context) {
sess, err := session.NewSession(&aws.Config{
Region: aws.String("us-west-2")},
)
// Create IAM service client
svc := iam.New(sess)
result, err := svc.GetAccountPasswordPolicy(&iam.GetAccountPasswordPolicyInput{})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"passwordPolicy": result.PasswordPolicy})
})
r.Run() // listen and serve on 0.0.0.0:8080
}
This code snippet is a simple Go application using the Gin framework. It includes an endpoint (/awsPolicy
) which returns the AWS IAM password policy for the account.
The vulnerability lies in the GetAccountPasswordPolicy
function. This function retrieves the account password policy, including whether password expiration is enabled or not. If the EnablePasswordExpiration
flag in the returned PasswordPolicy
object is false
, this means that the password expiration is not enabled, which is a security risk.
Good security practices suggest that credentials should be renewed every 90 days. Without automatic password expiration, old and potentially compromised passwords can continue to be used, increasing the risk of unauthorized access.
To fix this vulnerability, the EnablePasswordExpiration
flag should be set to true
, and the MaxPasswordAge
should be set to 90
(for 90 days) in the AWS IAM policy.
Steps
- Enable password expiration in the AWS IAM policy
- Set the password expiration period to 90 days
- Update the code to retrieve and enforce the password expiration policy
- Handle any errors that may occur during the retrieval or enforcement of the policy
Compliant code
package main
import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/iam"
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
r.GET("/awsPolicy", func(c *gin.Context) {
sess, err := session.NewSession(&aws.Config{
Region: aws.String("us-west-2")},
)
// Create IAM service client
svc := iam.New(sess)
// Set the password policy
_, err = svc.UpdateAccountPasswordPolicy(&iam.UpdateAccountPasswordPolicyInput{
AllowUsersToChangePassword: aws.Bool(true),
HardExpiry: aws.Bool(true),
MaxPasswordAge: aws.Int64(90), // Set password expiration to 90 days
MinimumPasswordLength: aws.Int64(8),
PasswordReusePrevention: aws.Int64(5),
RequireSymbols: aws.Bool(true),
RequireNumbers: aws.Bool(true),
RequireUppercaseCharacters: aws.Bool(true),
RequireLowercaseCharacters: aws.Bool(true),
})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
result, err := svc.GetAccountPasswordPolicy(&iam.GetAccountPasswordPolicyInput{})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"passwordPolicy": result.PasswordPolicy})
})
r.Run() // listen and serve on 0.0.0.0:8080
}
The updated code now includes a call to UpdateAccountPasswordPolicy
to set the password policy for the AWS account. The policy is set to:
- Allow users to change their password
- Enforce password expiration (hard expiry)
- Set the maximum password age to 90 days
- Set the minimum password length to 8 characters
- Prevent password reuse for the last 5 passwords
- Require at least one symbol, number, uppercase character, and lowercase character in the password
If there is an error while setting the password policy, the error is returned as a JSON response with a status code of 500 (Internal Server Error).
After setting the password policy, the code retrieves the current password policy using GetAccountPasswordPolicy
and returns it as a JSON response. If there is an error while retrieving the password policy, the error is returned as a JSON response with a status code of 500 (Internal Server Error).