The following chapter outlines authentication and session management requirements of the MASVS into technical test cases. Test cases listed in this chapter are focused on server side and therefore are not relying on a specific implementation on iOS or Android.
For all of the test cases below, it need to be investigated first what kind of authentication mechanism is used. There are different mechanisms available, to implement server side authentication, either:
- Cookie-Based Authentication using a session ID or
- Token-Based Authentication.
Cookie-Based Authentication is the traditional authentication mechanism used in web applications, which is stateful. In order to adopt to the different requirements of mobile apps, a shift to stateless authentication or Token-Based Authentication can be seen. A prominent example for this is JSON Web Token or JWT which can be part of an OAuth2 authentication and authorization framework.
OAuth2 is an authorization framework used to authorize an application to use a user account on an HTTP service for a limited time and, at the same time, preventing the client applications from having knowledge of any user credentials.
OAuth2 defines four roles:
- Resource Owner: the user owning the account.
- Client: the application that wants to access the user's account using the access tokens.
- Resource Server: hosts the user accounts.
- Authorization Server: verifies the identity of the user and issues access tokens to the application.
Note: The API fulfills both the resource and authorization server roles. Therefore we will refer to both as the API.
Here is a more detailed explanation of the steps in the diagram:
- The application requests authorization to access service resources from the user.
- If the user authorized the request, the application receives an authorization grant. The authorization grant might have different forms (explicit, implicit, etc).
- The application requests an access token from the authorization server (API) by presenting authentication of its own identity, and the authorization grant.
- If the application identity is authenticated and the authorization grant is valid, the authorization server (API) issues an access token to the application. The access token might have a companion refresh token. Authorization is complete.
- The application requests the resource from the resource server (API) and presents the access token for authentication. The access token might be used on different ways (e.g., as a bearer token).
- If the access token is valid, the resource server (API) serves the resource to the application.
These are some of the common best practices for OAuth2 on native apps:
User-agent:
- Use an external user-agent (the browser) instead of an embedded user-agent (e.g. WebView or internal client user interface) to prevent End-User Credentials Phishing (e.g. you do not want an app offering you a "Login with Facebook" to get your Facebook password). However, by using the browser, the app relies on the OS Keychain for server trust. This way it will not be possible to implement certificate pinning. A solution for this would be to restrict the embedded user-agent to only the relevant domain.
- The user should have a way to verify visual trust mechanisms (e.g., Transport Layer Security (TLS) confirmation, web site mechanisms).
- The client should validate the fully qualified domain name of the server to the public key presented by the server during connection establishment to prevent man-in-the-middle attacks.
Type of grant:
- Use code grant instead of implicit grant on native apps.
- When using code grant, implement PKCE (Proof Key for Code Exchange) to protect the code grant. Make sure that the server also implements it.
- The auth "code" should be short-lived and only used immediately after receiving it. Make sure that they only reside on transient memory and are not stored or logged.
Client secrets:
- No shared secret should be used as proof of the client's identity as this could lead to client impersonation ("client_id" already serves this purpose). If for some reason they do use client secrets, be sure that they are stored in secure local storage.
End-User credentials:
- The transmission of end-user credentials must be protected using transport-layer mechanisms such as TLS.
Tokens:
- Keep access tokens in transient memory.
- Access tokens must be securely transmitted via TLS.
- The scope and expiry time of access tokens should be reduced when end-to-end confidentiality cannot be guaranteed or when the token provides access to sensitive information or allows the execution of high risk actions.
- Remember that if the app uses access tokens as bearer tokens and no additional mechanism is used to identify the client, the attacker can access all resources associated with the token and its scope after stealing the tokens.
- Store refresh tokens in secure local storage as they are long-term credentials.
For additional best practices and detailed information please refer to the source documents:
- RFC6749 - The OAuth 2.0 Authorization Framework
- DRAFT - OAuth 2.0 for Native Apps
- RFC6819 - OAuth 2.0 Threat Model and Security Considerations.
-- TODO [Provide a general description of the issue "Testing OAuth2 implementation".] --
-- TODO [Describe how to assess this given either the source code or installer package (APK/IPA/etc.), but without running the app. Tailor this to the general situation (e.g., in some situations, having the decompiled classes is just as good as having the original source, in others it might make a bigger difference). If required, include a subsection about how to test with or without the original sources.] --
-- TODO [Confirm remark on "Use the <sup> tag to reference external sources, e.g. Meyer's recipe for tomato soup."] --
--TODO [Develop content on Testing OAuth2 implementation with source code] --
-- TODO [Describe how to test for this issue "Testing OAuth2 implementation" by running and interacting with the app. This can include everything from simply monitoring network traffic or aspects of the app’s behavior to code injection, debugging, instrumentation, etc.] --
-- TODO [Describe the best practices that developers should follow to prevent this issue "Testing OAuth2 implementation".] --
- M6 - Insecure Authorization - https://www.owasp.org/index.php/Mobile_Top_10_2016-M6-Insecure_Authorization
- V4.3 - "The remote endpoint uses server side signed tokens, if stateless authentication is used, to authenticate client requests without sending the user's credentials."
- CWE-285: Improper Authorization
-- TODO [Add relevant tools for "Testing OAuth2 implementation"] --
- OWASP ZAP - https://github.com/zaproxy/zaproxy
Applications often have different areas with, on the one hand public and non-privileged information and functions, and on the other hand sensitive and privileged information and functions. Users can legitimately access the first ones without any restriction; however, in order to make sure sensitive and privileged information and functions are protected and accessible only to legitimate users, proper authentication has to be in place.
Authentication always need to be handled in the server side code and should never rely on client-side controls. Client-side controls can be used to improve the user workflow and only allow specific actions, but there always need to be the server-side counterpart that defines what a user is allowed to access.
In case Token-Based authentication with JWT is used, please also look at the test case "Testing JSON Web Token (JWT)".
To review the authentication architecture you need access to source code of the remote service. Identify which authentication mechanism (token or cookie based) is used and make sure that an appropriate form of authentication is performed. What's appropriate depends on the type and sensitivity level of the app. You may use the OWASP Mobile AppSec Verification Standard as a guideline:
- Username/password authentication is recommended for level 1 (non-critical) apps.
- 2-factor authentication is recommended for level 2 (sensitive) apps.
Afterwards locate all APIs that provide sensitive information and functions, and verify that authorization is consistently enforced.
Ideally, authentication mechanisms shouldn't be implemented from scratch but built on top of proven frameworks. Many popular frameworks provide ready-made functionality for authentication and session management. If the app uses framework APIs for authentication, make sure to check the security documentation of these frameworks and verify that the recommended best practices have been followed. Examples for widely used frameworks on server side are:
To verify authentication, first all privileged endpoints a user can access within an app should be explored. For all requests sent to an endpoint, an interception proxy can be used to capture network traffic while being authenticated. Then, try to replay requests while removing the authentication information. If the endpoint is still sending back the requested data, that should only be available for authenticated users, authentication checks are not implemented properly on the endpoint.
Further attack methods can be found in the test case OTG-AUTHN-004 of the OWASP Testing Guide. The OWASP Testing Guide should also be consulted for more authentication test cases.
For every endpoint that needs to be protected, implement a mechanism that checks the session ID or token of the user:
- if there is no session ID or token, the user may not have been authenticated before;
- if a session ID or token exists, make sure that it is valid and that it grants the user with sufficient privileges to allow the user to access the endpoint.
If any of these two conditions raise an issue, reject the request and do not allow the user to access the endpoint.
- M4 - Insecure Authentication - https://www.owasp.org/index.php/Mobile_Top_10_2016-M4-Insecure_Authentication
- 4.1: "If the app provides users with access to a remote service, an acceptable form of authentication such as username/password authentication is performed at the remote endpoint."
- CWE-287: Improper Authentication
All significant, if not privileged, actions must be done after a user is properly authenticated; the application will remember the user inside a session. When improperly managed, sessions are subject to a variety of attacks where the session of a legitimate user may be abused, allowing the attacker to impersonate the user. As a consequence, data may be lost, confidentiality compromised or illegitimate actions performed.
Sessions must have a beginning and an end. It must be impossible for an attacker to forge a session ID: instead, it must be ensured that a session can only be started by the system on the server side. Also, the duration of a session should be as short as possible, and the session must be properly terminated after a given amount of time or after the user has explicitly logged out. It must be impossible to reuse session ID.
As such, the scope of this test is to validate that sessions are securely managed and cannot be compromised by an attacker.
When server source code is available, the tester should look for the place where sessions are initiated, stored, exchanged, verified and terminated. This must be done whenever any access to privileged information or action takes place. For those matters, automated tools or manual search can be used to look for relevant keywords in the target programming language. Sample frameworks on server side are:
A best practice is to crawl the application first, either manually or with an automated tool. The goal is to check if all parts of the application leading to privileged information or actions are protected and a valid session ID is required or not.
Then, you can use the crawled requests within any intercepting proxy to try to manipulate session IDs:
- by modifying them into illegitimate ones (for instance, add one to the valid session ID or delete parts of it).
- by deleting a valid one in the request to test if the information and/or function of the application can still be accessed.
- by trying to log out and re-log in again to check if the session ID has changed or not.
- when changing privilege level (step-up authentication). Try to use the former one (hence with a lower authorization level) to access the privileged part of the application.
- by trying to re-use a session ID after logging out.
Also the OWASP Testing Guide should be consulted for more session management test cases.
In order to offer proper protection against the attacks mentioned earlier, session IDs must:
- always be created on the server side,
- not be predictable (use proper length and entropy),
- always be exchanged over secure connections (e.g. HTTPS),
- be stored securely within the mobile app,
- be verified when a user is trying to access privileged parts of an application (a session ID must be valid and correspond to the proper level of authorization),
- be renewed when a user is asked to log in again to perform an operation requiring higher privileges and
- be terminated on server side and deleted within the mobile app when a user logs out or after a specified timeout.
It is strongly advised to use session ID generators that are build-in within the framework used, as they are more secure than building a custom one. Such generators exist for most frameworks and languages.
- M4 - Insecure Authentication - https://www.owasp.org/index.php/Mobile_Top_10_2016-M4-Insecure_Authentication
- 4.2: "The remote endpoint uses randomly generated session identifiers, if classical server side session management is used, to authenticate client requests without sending the user's credentials."
- CWE-613: Insufficient Session Expiration
- OWASP ZAP (Zed Attack Proxy)
- Burp Suite
JSON Web Token (JWT) ensures the integrity of information within a JSON object between two parties and is defined in RFC 7519. A cryptographic signature is created for the data within the token. This only allows the server to create and modify tokens and enables a stateless authentication. The server doesn't need to remember any session or any other authentication information, as everything is contained within JWT.
An example of an encoded JSON Web Token can be found below.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
JWTs are Base-64 encoded and are divided into three parts:
- Header Algorithm and Token Type (eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9):
{"alg":"HS256","typ":"JWT"}
- Claims Data (eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9):
{"sub":"1234567890","name":"John Doe","admin":true}
- JSON Web Signature (JWS) (TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ):
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
For mobile apps it's more and more used to authenticate both the message sender and receiver by using JWT. JWT implementations are available for all major programming languages, like PHP or Java Spring.
Identify the JWT library that is used on server and client side. Check if there are any known vulnerabilities available for the JWT libraries in use.
The following best practices should be checked in the JWT libraries:
- Verify the signature or HMAC on server-side at all times for all incoming requests containing a token.
- Verify where the private signing key or secret key for HMAC is located and stored. The key should always reside on the server side and never shared with the client. It should only be available for the issuer and verifier.
- Verify if encryption is used to encrypt the data embedded into JWT.
- Verify if replay attacks are addressed by using
jti
(JWT ID) claim, which provides a unique identifier for JWT.
Several known vulnerabilities in JWT should be checked while executing a dynamic analysis:
- Hashing algorithm
none
:- Modify the
alg
attribute in the token header and deleteHS256
and set it tonone
and use an empty signature (e.g. signature = ""). Use this token and replay it in a request. Some libraries treat tokens signed with the none algorithm as a valid token with a verified signature. This would allow an attacker to create their own "signed" tokens.
- Modify the
- Usage of asymmetric algorithms:
- JWT offers several asymmetric algorithms as RSA or ECDSA. In this case the private key will be used to sign the tokens and the verification will be done through the public key. If a server is expecting a token signed with an asymmetric algorithm as RSA, but actually receives a token signed with HMAC, it will think the public key is actually an HMAC secret key. The public key can now be misused as HMAC secret key in order to sign the tokens.
- Token Storage on client side:
- When using a mobile app that uses JWT it should be verified where the token is stored locally on the device.
- Cracking the signing key:
- Creating a signature of the token is done through a private key on server side. Once a JWT is obtained there are several tools available that can try to brute force the secret key offline. See the tools section for details.
- Information Disclosure:
- Decode the Base-64 encoded JWT and check what kind of data is transmitted within it and if it's encrypted or not.
Please also follow the test cases in the OWASP JWT Cheat Sheet and check the implementation of the logout as described in "Testing the Logout Functionality".
The following best practices should be considered, when implementing JWT:
- The latest version available of the JWT libraries in use should be implemented, to avoid known vulnerabilities.
- Make sure that tokens with a different signature type are guaranteed to be rejected.
- Store the JWT on the mobile phone using a secure mechanism, like KeyChain on iOS or KeyStore on Android.
- The private signing key or secret key for HMAC should only be available on server side.
- If replay attacks are a risk for the app,
jti
(JWT ID) claim should be implemented. - Ideally the content of JWT should be encrypted in order to ensure the confidentially of the information contained within it. There might be description of roles, usernames or other sensitive information available that should be protected. An example implementation in Java can be found in the OWASP JWT Cheat Sheet
- Clarify if copying a token to another device should or should not make an attacker able to continue authenticated. Check the device binding test case, if this should be enforced.
- M4 - Insecure Authentication - https://www.owasp.org/index.php/Mobile_Top_10_2016-M4-Insecure_Authentication
- 4.3: "The remote endpoint uses server side signed tokens, if stateless authentication is used, to authenticate client requests without sending the user's credentials."
- CWE-287: Improper Authentication
Reducing the lifetime of session identifiers and tokens to a minimum decreases the likelihood of a successful account hijacking attack. The scope for this test case is to validate that the application has a logout functionality and it effectively terminates the session on client and server side or invalidates a stateless token.
One of the most common errors done when implementing a logout functionality is simply not destroying the session object or invalidating the token on server side. This leads to a state where the session or token is still alive even though the user logs out of the application. If an attacker get’s in possession of valid authentication information he can continue using it and hijack a user account.
If server side code is available, it should be reviewed that the session is being terminated or token invalidated as part of the logout functionality. The check needed here will be different depending on the technology used. Here are different examples on how a session can be terminated in order to implement a proper logout on server side:
- Spring (Java) - http://docs.spring.io/spring-security/site/docs/current/apidocs/org/springframework/security/web/authentication/logout/SecurityContextLogoutHandler.html
- Ruby on Rails - http://guides.rubyonrails.org/security.html
- PHP - http://php.net/manual/en/function.session-destroy.php
For stateless authentication the access token and refresh token (if used) should be deleted from the mobile device and the refresh token should be invalidated on server side.
For a dynamic analysis of the application an interception proxy should be used. The following steps can be applied to check if the logout is implemented properly.
- Log into the application.
- Do a couple of operations that require authentication inside the application.
- Perform a logout operation.
- Resend one of the operations detailed in step 2 using an interception proxy. For example, with Burp Repeater. The purpose of this is to send to the server a request with the session ID or token that has been invalidated in step 3. If the logout is correctly implemented on the server side, either an error message or redirect to the login page will be sent back to the client. On the other hand, if you have the same response you had in step 2, then the token or session ID is still valid and has not been correctly terminated on the server side. A detailed explanation with more test cases, can also be found in the OWASP Web Testing Guide (OTG-SESS-006).
The logout function on the server side must invalidate the session identifier or token immediately after logging out to prevent it to be reused by an attacker that could have intercepted it (see Session Management Cheat Sheet).
Many mobile apps do not automatically logout a user, because of customer convenience by implementing stateless authentication. There should still be a logout function available within the application and this should work accordingly to best practices by also destroying the access and refresh token on client and server side. Otherwise this could lead to another authentication bypass in case the refresh token is not invalidated.
- M4 - Insecure Authentication - https://www.owasp.org/index.php/Mobile_Top_10_2016-M4-Insecure_Authentication
- 4.4: "The remote endpoint terminates the existing session or server side signed tokens when the user logs out."
- CWE-613: Insufficient Session Expiration
Password strength is a key concern when using passwords for authentication. Password policy defines requirements that end users should adhere to. Password length, password complexity and password topologies should properly be included in the password policy. A "strong" password policy makes it difficult or even infeasible for one to guess the password through either manual or automated means.
Regular Expressions are often used to validate passwords. The password verification check against a defined password policy need to be reviewed if it rejects passwords that violate the password policy.
Passwords can be set when registering accounts, changing the password or when resetting the password in a forgot password process. All of the available functions in the application that are able to change or set a password need to be identified in the source code. They should all be using the same password verification check, that is aligned with the password policy.
Here are different examples on how a validation can be implemented server-side:
If a framework is used that offers the possibility to create and enforce a password policy for all users of the application, the configuration should be checked.
All available functions that allow a user to set a password need to be verified, if passwords can be used that violate the password policy specifications. This can be:
- Self-registration function for new users that allows to specify a password,
- Forgot Password function that allows a user to set a new password or
- Change Password function that allows a logged in user to set a new password.
An interception proxy should be used, to bypass client passwords checks within the app in order to be able verify the password policy implemented on server side. More information about testing methods can be found in the OWASP Testing Guide (OTG-AUTHN-007)
A good password policy should define the following requirements in order to avoid password brute-forcing:
Password Length
- Minimum length of the passwords should be enforced, at least 10 characters.
- Maximum password length should not be set too low, as it will prevent users from creating passphrases. Typical maximum length is 128 characters.
Password Complexity
- Password must meet at least three out of the following four complexity rules
- at least one uppercase character (A-Z)
- at least one lowercase character (a-z)
- at least one digit (0-9)
- at least one special character (punctuation)
For further details check the OWASP Authentication Cheat Sheet. A common library that can be used for estimating password strength is zxcvbn, which is available for many programming languages.
- M4 - Insecure Authentication - https://www.owasp.org/index.php/Mobile_Top_10_2016-M4-Insecure_Authentication
- 4.5: "A password policy exists and is enforced at the remote endpoint."
- CWE-521: Weak Password Requirements
We all have heard about brute force attacks. This is one of the simplest attack types, as already many tools are available that work out of the box. It also doesn’t require a deep technical understanding of the target, as only a list of username and password combinations is sufficient to execute the attack. Once a valid combination of credentials is identified access to the application is possible and the account can be taken over. To be protected against these kind of attacks, applications need to implement a control to block the access after a defined number of incorrect login attempts. Depending on the application that you want to protect, the number of incorrect attempts allowed may vary. For example, in a banking application it should be around three to five attempts, but, in a app that doesn't handle sensitive information it could be a higher number. Once this threshold is reached it also needs to be decided if the account gets locked permanently or temporarily. Locking the account temporarily is also called login throttling. The test consists by entering the password incorrectly for the defined number of attempts to trigger the account lockout. At that point, the anti-brute force control should be activated and your logon should be rejected when the correct credentials are entered.
It need to be checked that a validation method exists during logon that checks if the number of attempts for a username equals to the maximum number of attempts set. In that case, no logon should be granted once this threshold is meet. After a correct attempt, there should also be a mechanism in place to set the error counter to zero.
For a dynamic analysis of the application an interception proxy should be used. The following steps can be applied to check if the lockout mechanism is implemented properly.
- Log in incorrectly for a number of times to trigger the lockout control (generally three to 15 incorrect attempts). This can be automated by using Burp Intruder.
- Once you have locked out the account, enter the correct logon details to verify if login is not possible anymore. If this is correctly implemented logon should be denied when the right password is entered, as the account has already been blocked.
Lockout controls have to be implemented on server side to prevent brute force attacks. Further mitigation techniques are described by OWASP in Blocking Brute Force Attacks. It is interesting to clarify that incorrect login attempts should be cumulative and not linked to a session. If you implement a control to block the credential in your 3rd attempt in the same session, it can be easily bypassed by entering the details wrong two times and get a new session. This will then give another two free attempts.
Alternatives to locking accounts are enforcing 2-Factor-Authentication (2FA) for all accounts or the usage of CAPTCHAS. See also Credential Cracking OAT-007 in the OWASP Automated Thread Handbook.
- M4 - Insecure Authentication - https://www.owasp.org/index.php/Mobile_Top_10_2016-M4-Insecure_Authentication
- 4.6: "The remote endpoint implements an exponential back-off, or temporarily locks the user account, when incorrect authentication credentials are submitted an excessive number of times ."
- CWE-307: Improper Restriction of Excessive Authentication Attempts
- Burp Suite Professional - https://portswigger.net/burp/
- OWASP ZAP - https://www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project
Compared to web applications most mobile applications don’t have a visible timeout mechanism that terminates the session ID or token after some period of inactivity and force the user to login again. For most mobile applications users need to enter the credentials once and use a stateless authentication mechanism. Mobile apps that handle sensitive data like patient data or critical functions like financial transactions should implement a timeout as a security-in-depth measure that forces users to re-login after a defined period of time. We will explain here how to check that this control is implemented correctly, both in the client and server side.
If server side code is available, it should be reviewed that the session timeout or token invalidation functionality is correctly configured and a timeout is triggered after a defined period of time. The check needed here will be different depending on the technology used. Here are different examples on how a session timeout can be configured:
- Spring (Java)
- Ruby on Rails
- PHP
- [ASP.Net](https://msdn.microsoft.com/en-GB/library/system.web.sessionstate.httpsessi onstate.timeout(v=vs.110).aspx)
In case of stateless authentication, once a token is signed, it is valid forever unless the signing key is changed or expiration explicitly set. One could use "exp" expiration claim to define the expiration time on or after which the JWT must not be accepted for processing. Speaking of tokens for stateless authentication, one should differentiate types of tokens, such as access tokens and refresh tokens. Access tokens are used for accessing protected resources and should be short-lived. Refresh tokens are primarily used to obtain renewed access tokens. They are rather long-lived but should expire too, as otherwise their leakage would expose the system for unauthorized use.
The exact values for token expiration depend on the application requirements and capacity. Sample code for JWT token refreshments is presented below:
app.post('/refresh_token', function (req, res) {
// verify the existing token
var profile = jwt.verify(req.body.token, secret);
// if more than 14 days old, force login
if (profile.original_iat - new Date() > 14) { // iat == issued at
return res.send(401); // re-logging
}
// check if the user still exists or if authorization hasn't been revoked
if (!valid) return res.send(401); // re-logging
// issue a new token
var refreshed_token = jwt.sign(profile, secret, { expiresInMinutes: 60*5 });
res.json({ token: refreshed_token });
});
Dynamic analysis is an efficient option, as it is easy to validate if the session timeout is working or not at runtime using an interception proxy. This is similar to test case "Testing the Logout Functionality", but we need to leave the application in idle for the period of time required to trigger the timeout function. Once this condition has been launched, we need to validate that the session is effectively terminated on client and server side.
The following steps can be applied to check if the session timeout is implemented properly.
- Log into the application.
- Do a couple of operations that require authentication inside the application.
- Leave the application in idle until the session expires (for testing purposes, a reasonable timeout can be configured, and amended later in the final version) Resend one of the operations executed in step 2 using an interception proxy, for example with Burp Repeater. The purpose of this is to send to the server a request with the session ID that has been invalidated when the session has expired. If session timeout has been correctly configured on the server side, either an error message or redirect to the login page will be sent back to the client. On the other hand, if you have the same response you had in step 2, then, this session is still valid, which means that the session timeout is not configured correctly. More information can also be found in the OWASP Web Testing Guide (OTG-SESS-007).
Most of the frameworks have a parameter to configure the session timeout. This parameter should be set accordingly to the best practices specified of the documentation of the framework. The best practice timeout setting may vary between 10 minutes to two hours, depending on the sensitivity of your application and the use case of it.
- M4 - Insecure Authentication - https://www.owasp.org/index.php/Mobile_Top_10_2016-M4-Insecure_Authentication
- 4.8: "Sessions and server side signed tokens are terminated at the remote endpoint after a predefined period of inactivity."
- CWE-613: Insufficient Session Expiration
Two-factor authentication (2FA) is becoming a standard when logging into mobile apps. Typically the first factor might be credentials (username/password), followed by a second factor which could be an One Time Password (OTP) sent via SMS. The key aspect of 2FA is to use two different factors out of the following categories:
- Something you have: this can be a physical object like a hardware token, a digital object like X.509 certificates (in enterprise environments) or generation of software tokens on the mobile phone itself.
- Something you know: this can be a secret only known to the user like a password.
- Something you are: this can be biometric characteristics that identify the users like TouchID.
Applications that offer access to sensitive data or critical functions, might require users additionally to re-authenticate with a stronger authentication mechanism. For example, after logging in via biometric authentication (e.g. TouchID) into a banking app, a user might need to do a so called "Step-up Authentication" again through OTP in order to execute a bank transfer.
A key advantage of step-up authentication is improved usability for the user. A user is asked to authenticate with the additional factor only when necessary.
When server-side source code is available, first identify how a second factor or step-up authentication is used and enforced. Afterwards locate all endpoints with sensitive and privileged information and functions: they are the ones that need to be protected. Prior to accessing any item, the application must make sure the user has already passed 2FA or the step-up authentication and that he is allowed to access the endpoint.
2FA or step-up authentication shouldn't be implemented from scratch, instead they should be build on top of available libraries that offer this functionality. The libraries used on the server side should be identified and the usage of the available APIs/functions should be verified if they are used accordingly to best practices.
For example server side libraries like GoogleAuth can be used. Such libraries rely on a widely accepted mechanism of implementing an additional factor by using Time-Based One-Time Password Algorithms (TOTP). TOTP is a cryptographic algorithm that computes a OTP from a shared secret key between the client and server and the current time. The created OTPs are only valid for a short amount of time, usually 30 to 60 seconds.
Instead of using libraries in the server side code, also available cloud solutions can be used like for example:
Regardless if the implementation is done within the server side or by using a cloud provider, the TOTP app need to be started and will display the OTP that need to be keyed in into the app that is waiting to authenticate the user.
For local biometric authentication as an additional factor, please verify the test case "Testing Biometric Authentication".
First, all privileged endpoints a user can only access with step-up authentication or 2FA within an app should be explored. For all of these requests sent to an endpoint, an interception proxy can be used to capture network traffic. Then, try to replay requests with a token or session information that hasn't been elevated yet via 2FA or step-up authentication. If the endpoint is still sending back the requested data, that should only be available after 2FA or step-up authentication, authentication checks are not implemented properly on the endpoint.
The recorded requests should also be replayed without providing any authentication information, in order to check for a complete bypass of authentication mechanisms.
Another attack is related to the case "Testing Excessive Login Attempts" - given that many OTPs are just numeric values, if the accounts are not locked after N unsuccessful attempts on this stage, an attacker can bypass second factor by simply bruterorcing the values within the range at the lifespan of the OTP. For 6-digit values and 30-second time step there's more than 90% probability to find a match within 72 hours.
The implementation of a second or multiple factors should be strictly enforced on server-side for all critical operations. If cloud solutions are in place, they should be implemented accordingly to best practices.
Step-up authentication should be optional for the majority of user scenarios and only enforced for critical functions or when accessing sensitive data.
Account lockouts for the second factor should be implemented the same way as for non-2FA cases (see "Testing Excessive Login Attempts" and [5]).
Regardless of 2FA or step-up authentication, additionally it should be supplemented with passive contextual authentication, which can be:
- Geolocation
- IP address
- Time of day
Ideally the user's context is compared to previously recorded data to identify anomalies that might indicate account abuse or potential fraud. This is all happening transparent for the user, but can become a powerful control in order to stop attackers.
An additional control to ensure that an authorized user is using the app on an authorized device is to verify if device binding controls are in place. Please check also "Testing Device Binding" for iOS and Android.
- M4 - Insecure Authentication - https://www.owasp.org/index.php/Mobile_Top_10_2016-M4-Insecure_Authentication
- 4.9: "A second factor of authentication exists at the remote endpoint and the 2FA requirement is consistently enforced."
- 4.10: "Step-up authentication is required to enable actions that deal with sensitive data or transactions."
- CWE-287: Improper Authentication
- CWE-308: Use of Single-factor Authentication
-- TODO [Provide a general description of the issue "Testing User Device Management".] --
-- TODO [Describe how to assess this given either the source code or installer package (APK/IPA/etc.), but without running the app. Tailor this to the general situation (e.g., in some situations, having the decompiled classes is just as good as having the original source, in others it might make a bigger difference). If required, include a subsection about how to test with or without the original sources.] --
-- TODO [Confirm remark on "Use the <sup> tag to reference external sources, e.g. Meyer's recipe for tomato soup."] --
--TODO [Develop content on Testing User Device Management with source code] --
-- TODO [Describe how to test for this issue "Testing User Device Management" by running and interacting with the app. This can include everything from simply monitoring network traffic or aspects of the app’s behavior to code injection, debugging, instrumentation, etc.] --
-- TODO [Describe the best practices that developers should follow to prevent this issue "Testing User Device Management".] --
- M4 - Insecure Authentication - https://www.owasp.org/index.php/Mobile_Top_10_2016-M4-Insecure_Authentication
- 4.11: "The app informs the user of all login activities with his or her account. Users are able view a list of devices used to access the account, and to block specific devices."
-- TODO [Add relevant CWE for "Testing User Device Management"] --
-- TODO [Add relevant tools for "Testing User Device Management"] --