In 2021, broken access control moved up from fith to be the number one cyber security risk faced by web applications on the OWASP Top Ten, while at the end of 2020, HackerOne reported that improper access control and information disclosure security vulnerabilities increased by 134% and 63% respectively year on year. These vulnerabilities are difficult to detect with automated tools. In this blog we describe for the first time an improper access control vulnerability Opsmorph discovered in authorization logic common in applications built on Amazon Web Services (AWS). The vulnerability has since been patched by AWS.
Group Based Authorization Control on AWS
Amazon API Gateway is a managed REST API service on AWS that serves as a web facing entry point that controls access to data and resources in the cloud. Amazon Cognito is a managed authentication and authorization service for user sign-up, sign-in, and access control for web and mobile apps. Amazon Cognito User Pools together with Cognito User Groups enable you to create sets of users to control their authorization and access to resources and information.
In some web applications, users are permitted to create private groups and to act as administrators, permitting access only to approved people. Opsmorph discovered a vulnerability in authorization checks common in applications that implement this functionality using Cognito User Groups, API Gateway, and a Cognito User Pool Authorizer that meant that a user with permission to create a new Cognito User Group could fool authorization checks into thinking that the user is in any other existing Cognito User Group in the same User Pool, referred to as user group spoofing.
A typical flow is as follows. When a user of an application wants to access data stored in the cloud, they submit a request to API Gateway together with a token in the request headers that enables the application to identify the user making the request. If the token is valid, then the information it contains, including which groups the user is in, is further examined for authorization control to prevent users getting access to information they are forbidden to obtain. The most convenient way to implement authentication of the token in API Gateway when also using Cognito is to use a Cognito User Pool Authorizer. When the Cognito User Pool Authorizer was released, AWS described its advantages :
“API Gateway has recently launched support for Cognito User Pool Authorizer. If you use Cognito User Pool Authorizer, you do not need to set up your own custom authorizer to validate tokens. Once your API methods are configured with Cognito User Pool Authorizer, you can pass unexpired ID Token in the Authorization header to your API methods. If it’s a valid ID Token for a user of your User Pool, you can then access all the claims of ID Token in your API using ‘$context.authorizer.claims’. For example ‘$context.authorizer.claims.email’ will return user’s email address and ‘$context.authorizer.claims.sub’ will return you user’s unique identifier. If the ID token is expired or is invalid, Cognito User Pool Authorizer will send Unauthorized (401) response to the caller.”
Integrating Amazon Cognito User Pools with API Gateway - AWS, 31 May 2016
User Group Spoofing by Injection
Opsmorph showed that when API Gateway is secured with a Cognito User Pool Authorizer it concatenates group names from the identity token into a comma separated string and, as Cognito also permits commas in the group names, this was an ambiguous representation of the groups a user was in that provided an opportunity for injection type attacks. Consequently, the groups claim of the token after the Cognito User Pool Authorizer was not a trustworthy claim and could be exploited by a malicious user of the application. Any authorization logic that tried to split the concatenated string on commas to check group information for authorization would split apart group names with commas in them in a way that could be manipulated. It is likely that most application logic using the groups claim in a Cognito User Pool Authorizer involves splitting of the groups claim on commas and this is something that would typically be implemented either in the mapping template of API Gateway or in a Lamda function.
As an example, suppose a Cognito group exists called “Admins” that is restricted to the most privileged users of the application. If a hacker created a new group called “Admins,Hackers” the Cognito User Pool Authorizer would have represented membership of this group in the same way it would represent a user being in a group called “Admins” and a group called “Hackers”. Authorization logic splitting that representation on commas would think the hacker from the "Admins,Hackers” group was in two groups, one called “Admins” and one called “Hackers”, thus granting them access to the “Admins” group and its elevated privileges even though they were not a member.
Resolving the vulnerability
Opsmorph immediately informed AWS about the user group spoofing vulnerability and put together video demonstrations of test web applications that could be vulnerable to such an attack. One video demonstrated an example of a company web chat application that enabled its staff to create new group chats. In this example, a member of staff could create a group with a suitable name containing a comma that would grant them access to other departments private groups they were not a member of, thereby obtaining confidential information.
As a result of Opsmorph’s research AWS have been able to make changes to the Cognito User Pool Authorizer so that it now escapes special characters when parsing the groups claim of the token. For example, if a user was in a group called “Admin,Hackers” this would now be parsed by the Cognito User Pool Authorizer as “Admin%2CHackers” and application logic that splits on commas will no longer split this into “Admins” and “Hackers” as it did before. In addition to this change, AWS also added this note to the API Gateway documentation which advises developers to:
“Ensure that user-defined Amazon Cognito variables such as groups, users, and roles use only alphanumeric characters.”
Create an Amazon Cognito user pool for a REST API - AWS
Furthermore, AWS have provided this blog post on using a Cognito User Pool Authorizer in which they now advise that whenever users want to validate and utilize the claims of the token, they should not use the Cognito Pool Authorizer but instead:
“To validate the claims (and additional claims) in the access tokens and ID tokens issued by Amazon Cognito, use a Lambda authorizer. If you're using access tokens to authorize API method calls, make sure that you authorize access to your APIs using custom scopes in Amazon Cognito.”
How do I set up an Amazon Cognito user pool as an authorizer on an API Gateway REST API? - AWS, 30 March 2021
Opsmorph are proud to have helped Amazon Web Services and their customers strengthen the security of applications built on AWS. For more details on Opsmorph’s services in cloud-based web applications and machine learning check out the website or drop us an email.