Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Java: Add query for insecure local authentication #15481

Merged
merged 11 commits into from
Feb 12, 2024

Conversation

joefarebrother
Copy link
Contributor

This query finds instances of local authentication callbacks that don't use a CryptoObject.

@joefarebrother joefarebrother changed the title [Draft] Add query for insecure local authentication [Draft] Java: Add query for insecure local authentication Jan 31, 2024
@github-actions github-actions bot added the Java label Jan 31, 2024
Copy link
Contributor

github-actions bot commented Feb 2, 2024

QHelp previews:

java/ql/src/Security/CWE/CWE-287/AndroidInsecureLocalAuthentication.qhelp

Insecure local authentication

Biometric local authentication such as fingerprint recognition can be used to protect sensitive data or actions within an application. However, if this authentication does not use a KeyStore-backed key, it can be bypassed by a privileged malicious application, or by an attacker with physical access using application hooking tools such as Frida.

Recommendation

Generate a secure key in the Android KeyStore. Ensure that the onAuthenticationSuccess callback for a biometric prompt uses it in a way that is required for the sensitive parts of the application to function, such as by using it to decrypt sensitive data or credentials.

Example

In the following (bad) case, no CryptoObject is required for the biometric prompt to grant access, so it can be bypassed.

biometricPrompt.authenticate(
    cancellationSignal,
    executor,
    new BiometricPrompt.AuthenticationCallback {
        @Override
        // BAD: This authentication callback does not make use of a `CryptoObject` from the `result`.
        public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) {
            grantAccess()
        }
    }
)

In the following (good) case, a secret key is generated in the Android KeyStore. The application requires this secret key for access, using it to decrypt data.

private void generateSecretKey() {
    KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(
        "MySecretKey",
        KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
        .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
        .setUserAuthenticationRequired(true)
        .setInvalidatedByBiometricEnrollment(true)
        .build();
    KeyGenerator keyGenerator = KeyGenerator.getInstance(
            KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
    keyGenerator.init(keyGenParameterSpec);
    keyGenerator.generateKey();
}


private SecretKey getSecretKey() {
    KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
    keyStore.load(null);
    return ((SecretKey)keyStore.getKey("MySecretKey", null));
}

private Cipher getCipher() {
    return Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
            + KeyProperties.BLOCK_MODE_CBC + "/"
            + KeyProperties.ENCRYPTION_PADDING_PKCS7);
}

public prompt(byte[] encryptedData) {
    Cipher cipher = getCipher();
    SecretKey secretKey = getSecretKey();
    cipher.init(Cipher.DECRYPT_MODE, secretKey);

    biometricPrompt.authenticate(
        new BiometricPrompt.CryptoObject(cipher),
        cancellationSignal,
        executor,
        new BiometricPrompt.AuthenticationCallback() {
            @Override
            // GOOD: This authentication callback uses the result to decrypt some data.
            public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) {
                Cipher cipher = result.getCryptoObject().getCipher();
                byte[] decryptedData = cipher.doFinal(encryptedData);
                grantAccessWithData(decryptedData);
            }
        }
    );
}

References

@joefarebrother joefarebrother changed the title [Draft] Java: Add query for insecure local authentication Java: Add query for insecure local authentication Feb 2, 2024
Copy link
Contributor

@atorralba atorralba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code LGTM. Just a handful of comments/questions. After resolving them, and assuming DCA and MRVA look good, feel free to go ahead with the docs review.

<overview>
<p>
Biometric local authentication such as fingerprint recognition can be used to protect sensitive data or actions within an application.
However, if this authentication does not make use of a <code>KeyStore</code>-backed key, it is able to be bypassed by a privileged malicious application or an attacker with physical access.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we specify that the risk we're trying to defend against is application hooking (with e.g. Frida)?

* @description Local authentication that does not make use of a `CryptoObject` can be bypassed.
* @kind problem
* @problem.severity warning
* @security-severity 9.3
Copy link
Contributor

@atorralba atorralba Feb 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should reduce this score. See this CVE for instance, it's the same issue and it has a 6.7 CVSS.

IMHO, I think we could get it even lower. The CVSS vector that makes sense for me is AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H, which has a 4.4 score.

Suggested change
* @security-severity 9.3
* @security-severity 4.4

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the 4.4 obtained by taking the average of the base/impact/exploitability metrics?
This page appears to output 6.7 as an overall CVSS score.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I copied the wrong link 😅 It's 4.4 when you reduce the Integrity and Availability scores to None (since we're only considering the Confidentiality impact of accessing data protected by biometrics): https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vector=AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N&version=3.1

@joefarebrother joefarebrother added the ready-for-doc-review This PR requires and is ready for review from the GitHub docs team. label Feb 9, 2024
subatoi
subatoi previously approved these changes Feb 9, 2024
Copy link
Contributor

@subatoi subatoi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Just the usual minor suggestions

@subatoi subatoi self-assigned this Feb 9, 2024
Co-authored-by: Ben Ahmady <32935794+subatoi@users.noreply.github.com>
Copy link
Contributor

@subatoi subatoi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

@joefarebrother joefarebrother merged commit 75a2b94 into github:main Feb 12, 2024
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Java ready-for-doc-review This PR requires and is ready for review from the GitHub docs team.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants