mirror of
https://github.com/github/codeql.git
synced 2026-04-24 08:15:14 +02:00
Add documentation
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
Biometric local authentication such as fingerprint recognistion 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.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
Generate a secure key in the Android <code>KeyStore</code> and ensure that the <code>onAuthenticaionSuccess</code> 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.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>In the following (bad) case, no <code>CryptoObject</code> is required for the biometric prompt to grant access, so it can be bypassed.</p>
|
||||
<sample src="AndroidInsecureLocalAuthenticationBad.java" />
|
||||
<p>In he following (good) case, a secret key is generated in the Android <code>KeyStore</code> that is required for the application to grant access.</p>
|
||||
<sample src="AndroidInsecureLocalAuthenticationGood.java" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
OWASP Mobile Application Security: <a href="https://mas.owasp.org/MASTG/Android/0x05f-Testing-Local-Authentication/">Android Local Authentication</a>
|
||||
</li>
|
||||
<li>
|
||||
OWASP Mobile Application Security: <a href="https://mas.owasp.org/MASTG/tests/android/MASVS-AUTH/MASTG-TEST-0018/">Testing Biometric Authentication</a>
|
||||
</li>
|
||||
<li>
|
||||
WithSecure: <a href="https://labs.withsecure.com/publications/how-secure-is-your-android-keystore-authentication">How Secure is your Android Keystore Authentication?</a>
|
||||
</li>
|
||||
<li>
|
||||
Android Developers: <a href="https://developer.android.com/training/sign-in/biometric-auth">Biometric Authentication</a>
|
||||
</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,11 @@
|
||||
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()
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,48 @@
|
||||
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() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user