Author: Carlo Valentin - Dec. 2018
This document provides guidelines for how to implement authentication and authorization in Unity applications.These guidelines will cover general points like:
- Use a Trusted Identity Provider
- Require Multi-Factor Authentication for Sensitive Applications
- Limit OAuth2 Scope by the Principle of Least Privilege
- Limited Token Lifetimes
- Validating OAuth2 Redirect URIs
- Validating the OAuth2 State Parameter
Authentication is the process of verifying the user’s identity typically through an initial login and subsequently by verifying a unique secret identifier on each HTTP request made by the user’s browser.
Authorization is the process of ensuring a user can only access resources they are supposed to, usually based on some role or Risk Rating that is defined according to business logic.
During login, the user should be prompted for at least one second factor of authentication for sensitive services. Sensitive services typically include, but are not limited to: administrative panels, services that handle PII or payment information, and flagship service.
By adding multiple layers of verification we can ensure that a user’s account is not compromised, especially for sensitive applications and services. This will ensure in the case where a password (the most common initial factor of authentication) is not enough to compromise a user’s account.
Contact the appropriate identity provider to be used at Unity, and require 2FA if needed.
Medium
When an OAuth2 client, a scope is defined for the the client. This scope determines which backend APIs are accessible to the client after performing authentication via the auth provider. When setting up a new OAuth2 client, the team requesting the client should identify what APIs/data they need access to, and limit the scope to those specific APIs.
Limiting the scope of our APIs is a best practice that can limit the impact of a successful attack. Also, often it is a Unity ID user that is authenticating using the given scope, and with the given access token will give the user direct access to the APIs. Since this is publicly accessible, care should be taken that the user cannot access sensitive APIs, in particular, APIs that handle personally identifiable information (PII).
During the requirements phase, determine what information is needed for the OAuth2 client, and limit the APIs to only what is necessary. If possible, work with the auth provider to build a custom scope that will limit access to wider APIs.
Medium
When authenticating, a variety of tokens are used to prove the identity of a user. This is typically through a session cookie, or an access token attached to a user’s account. These tokens should have the shortest lifetime that balances the needs of the users with security. Tokens should not be valid for an infinite length of time, and should expire within a reasonable timeframe.
This is primarily a defense-in-depth measure, focusing on limiting the impact of an attack if these tokens are compromised. This also decreases the attack surface of a resulting application, reducing the number of valid tokens at any given time.
Check all tokens related to authentication, and review their lifetimes. If you are unsure, contact security for recommendations on their lifetimes. When possible, use the shortest lifetime within a reasonable use.
Medium
When performing the OAuth2 login flow, a redirect URI is used to securely send the access token to the client web application, after it has authenticated with the auth provider. This is provided by the client during the OAuth2 flow. This URI should be validated to ensure it is a known URI that is used by the OAuth2 client.
This prevents a potential information disclosure attack when there is an open redirect on a valid redirect URI. This results in a user’s OAuth token being potentially leaked, compromising their account.
Validate the entire URI against a whitelist of known valid URIs. Avoid using regular expressions or substring matching.
Good Example:
def validate_redirect_uri(redirect_uri):
if redirect_uri == "https://newservice.unity3d.com/validate_oauth" :
return True;
return False;
Bad Example
def validate_redirect_uri(redirect_uri):
if "unity3d.com" in redirect_uri:
return True;
return False;
High
When starting the initial OAuth2 flow, the client has the option of providing a state parameter. This state parameter is then sent back with the authorization to be validated by the client later in the flow. This state parameter should be generated upon the initial OAuth2 request, and stored to validate once the authorization from the auth provider has occurred.
This is to ensure that the OAuth2 flow is initiated by the user, and is not vulnerable to a potential CSRF (Cross-Site Request Forgery). By ensuring that the user has initiated the OAuth2 flow, they will be performing actions within their account with known permissions.
Generate a cryptographically-secure random state parameter when the OAuth2 flow is initialized. The client should validate this when it is returned through the redirect URI callback. The parameter should only be valid for the same OAuth2 flow that initiated it.
Low