In some companies, multiple systems are operated, and separate accounts are managed for each system. Users who use these systems need to remember the accounts for all the systems they access and must log in separately to each system, which can be inconvenient. Additionally, administrators who manage these systems face increased challenges due to the fragmented member information across multiple systems.
By implementing SSO (Single Sign-On), these issues can be resolved. Users only need to remember one account and can log in once to access multiple systems. Administrators can also manage member information in a single location, reducing the number of management points.
There are several ways to implement SSO, but these can generally be summarized into two main approaches. The first approach, which was widely used in the past, involves using CAS (Central Authentication Service), an open-source server dedicated to SSO. The second approach utilizes OAuth 2, which provides authorization flows
for accessing service resources, and is more adaptable for extending to web, mobile, desktop, and IoT devices.
In the following two posts, I will explain how to build an SSO environment using OAuth 2. In this post, I will first cover the concepts of OAuth 2 and considerations for its implementation. In the next post, I will explain how to extend OAuth 2 for an SSO environment and how to set up SSO using Spring Boot and Spring Security with OAuth.
OAuth2
To access protected resources on a specific system via an API, the user must know their authentication information (username, password) for that system. Managing and using authentication information for other systems at the system level can cause many security issues. To avoid these problems, an alternative approach is to delegate authentication through APIs.
Many service providers (Google, Yahoo, AOL, etc.) implemented such authentication methods separately. These implementations were slightly different from one another and not compatible. To standardize these practices, the OAuth 1.0 specification was created. After several years of use and addressing the issues in OAuth 1.0, the community created OAuth 2 (hereafter referred to as "OAuth").
- Complexity of encryption requirements
- Limited support for web-based applications only
- Difficulty in performance scaling
1. OAuth Roles
OAuth defines four roles to manage delegated authorization, as summarized in the table below.
2. Authorization Grant Types
To request an access token, the client must receive authorization from the resource owner. OAuth offers various authorization grant types for different use cases. The four authorization grant types defined by OAuth are:
2.1. Authorization Code Grant
The authorization code grant flow is based on HTTP redirection. The client must interact with the resource owner's web browser and handle requests from the authorization server. The flow is as follows:
- The client redirects the user agent to the authorization server (with a state value and a redirect URI to receive the response).
- If there is no valid authentication history, the authorization server responds with a login page.
- The resource owner authorizes the client via the authorization server.
- The authorization server redirects to the client with the authorization code (and state value).
- The client requests the access token from the authorization server, providing the authorization code and client authentication information.
This method offers significant security benefits, as the client goes through an authentication process, and the access token is transmitted only between the authorization server and the client.
2.2. Implicit Grant
Implicit grant is used for clients operating in a browser, such as those using JavaScript. It is suitable when the web browser is trusted, and there is little risk of exposure to malicious users or applications. It is commonly used in mobile apps or web applications running on devices. The flow is as follows:
- The client redirects the user agent to the authorization server (with state value and redirect URI).
- If there is no valid authentication history, the authorization server responds with a login page.
- The resource owner authorizes the client via the authorization server.
- The authorization server responds with the access token.
- The client receives the access token.
Since access tokens cannot be refreshed, if they expire, the client must repeat the authorization flow to obtain a new token.
2.3. Resource Owner Password Grant
This method exchanges the username and password for an access token. The flow is as follows:
- The client requests the user's credentials.
- The client sends the credentials along with its information to the authorization server to request an access token.
- The authorization server responds with the access token.
This method exposes the resource owner's password to the client, and should only be used when other grant types are not feasible.
2.4. Client Credentials Grant
The client credentials grant is used when the client does not need to delegate access on behalf of the resource owner, or when access has already been granted externally. It is commonly used for applications accessing resources unrelated to specific users. The flow is as follows:
- The client sends a request containing its credentials to the authorization server.
- The authorization server responds with the access token.
- This method should be used carefully, especially when sensitive client authentication is involved. In such cases, it is essential to rotate credentials regularly.
3. Choosing the Right Authorization Grant Type
If the client operates on behalf of a resource owner and the user is using a web browser, the authorization code grant or implicit grant can be used. The choice depends on the client’s situation. For clients with a lifecycle within the browser, the implicit grant is preferable, while the authorization code grant is a safer and more flexible option.
For clients that operate independently of the user, the client credentials grant is suitable.
If simple user authentication information is available and no other methods can be used, the resource owner password grant can be employed.
4. Security Considerations When Implementing OAuth
When implementing OAuth, there are three systems to consider: the client, the authorization server, and the resource server. Each system has its own security considerations, and the security of the issued access tokens must also be addressed.
4.1. Client Security Considerations
-
CSRF (Cross-Site Request Forgery) Attacks
CSRF is a well-known attack where a malicious application causes the user's browser to make requests to an authenticated website without the user's consent. A common solution is to add unpredictable elements to each HTTP request. Using a 'state' parameter is recommended to prevent CSRF attacks. -
Client Information Attacks
Implicit grant clients are often JavaScript-based applications, where hiding the Client Secret is challenging. Using dynamic client registration during runtime can help mitigate this risk. The client ID and secret are generated and managed during the OAuth flow and are unique for each client instance. -
Redirect URI Registration
When registering client information with the authorization server, the redirect URI must be as precise as possible to avoid security vulnerabilities.3-1) Referrer-based Authorization Code Theft
Attackers can intercept the authorization code using the HTTP referrer header. This can occur if the client redirects to an attacker-controlled page under the valid redirect URI.3-2) Open Redirector-based Access Token Theft
Attackers can exploit open redirect vulnerabilities to steal the access token during the implicit grant flow. -
Authorization Code Theft
If a client is public, attackers can intercept the authorization code easily. -
Access Token Theft
Attackers' main goal is often to steal the access token, which grants unauthorized access to resources.
4.2. Authorization Server Security Considerations
-
Session Hijacking
Authorization codes are passed as query parameters and are stored in the browser history, which can be vulnerable to session hijacking if the attacker reuses the code from the history. -
Redirect URI Validation
It is crucial to validate the redirect URI to ensure that the redirect URI registered with the authorization server matches the URI provided in the query parameters. -
Client Validation
The authorization server must validate that the client sending the request is the same client that was initially registered. -
Scope Validation Errors
If the scope value is incorrect or missing, the authorization server should return an error rather than redirecting to a URI.
4.3. Resource Server Security Considerations
-
Resource Endpoint Design
Be cautious about XSS vulnerabilities when designing REST APIs. Employ methods such as escaping query parameters to avoid attacks. -
Same-Origin Policy Issues
Use solutions that handle cross-origin issues, especially when OAuth is used to secure APIs across domains. -
Token Lifespan
Keep access tokens' lifespans relatively short to minimize the risk of long-term exploitation in case they are compromised.
4.4. Access Token Security Considerations
OAuth specifications define bearer tokens as security devices. The party in possession of this token can use it regardless of who they are. Therefore, access rights are granted to the client, and it does not matter who is using it.
-
Risks and Considerations in Using Bearer Tokens
There is a risk that the access token could be forged. An attacker could create their own forged token or modify a valid token, allowing the resource server to grant inappropriate access to the client. Alternatively, an attacker might extend the validity of the token itself.
An attacker may attempt to use a previously used token. In this case, the resource server should not return valid data. Instead, it should return an error.
An attacker could also use token redirection. In this case, the attacker uses a token issued for one resource server and attempts to access another resource server, believing the token to be valid. The attacker might try to get an access token for a specific resource server and display this token as valid for accessing other resources. -
Protecting the Transmission of Bearer Tokens
Care should be taken to prevent access tokens from being transmitted through unsecured channels. As specified in the OAuth framework, the transmission of access tokens should be protected using SSL/TLS, an encryption protocol designed to secure network communications. -
Considerations for Clients
One measure that clients can apply is to restrict the token's scope to the minimum necessary for the task. If only the minimum resources of the resource owner are required, it is important to grant only the least amount of permission needed. Additionally, if possible, it is better to store the access token temporarily in memory. Storing the token in a database or other storage risks exposure if an attacker gains access to the database or storage. -
Considerations for Authorization Servers
In most cases, the authorization server stores access tokens in a database. Therefore, if an attacker gains access to the authorization server's database or can perform SQL injection, the security of multiple resource owners may be compromised. The authorization server can choose to store a hash of the access token (e.g., SHA-256) instead of the actual token text. In this case, even if the attacker steals the entire database containing all access tokens, there is little they can do with the leaked information.
To minimize the risks associated with the leakage of a single access token, it is recommended to keep the access token's lifespan short. If the client needs prolonged access to a resource, the authorization server can issue a refresh token to the client.
Ultimately, one of the best practices the authorization server can implement is secure logging. By logging when tokens are issued, used, or revoked, suspicious activities can be monitored. These logs should be kept secure and not exposed. -
Considerations for Resource Servers
The resource server should properly validate the token and avoid using access tokens with special powers that have a superuser-like role.
References and Websites:
- Ryan Boyd. (2012). Safe API Authentication and Authorization with OAuth 2.0 (translated by Lee Jeong-rim). Seoul: Hanbit Media.
- Justin Richer, Antonio Sanso. (2016). OAuth 2 in Action. Manning Publications
- "The OAuth 2.0 Authorization Framework". October, 2012. https://tools.ietf.org/html/rfc6749
- "An Introduction to OAuth 2". July 21, 2014. https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2
- "OAuth 2.0 API". http://developer.okta.com/docs/api/resources/oauth2.html#basic-flows
- "Understanding OAuth2". January 22, 2016. http://www.bubblecode.net/en/2016/01/22/understanding-oauth2/