Weak credential policy - Password Expiration - Go
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
Insecure Code Example
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
Secure Code Example
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).
References
Last updated
2023/09/18