Insecure password storage
Insecure password storage
Description
Insecure storage of password could lead to account compromise. The vulnerability is the result of storing password using insecure methods that are susceptible to unauthorized access or compromise.
The following example shows insecure storage of password credentials in cookies:
response.addCookie(new Cookie("password", password));
Recommendation
To safely store account credentials, consider the following recommendations:
- For Android, use
AccountManager
to store account credentials. - For iOS, use
keychain
to store account credentials.
import android.accounts.Account
import android.accounts.AccountManager
import android.content.Context
fun saveCredentials(context: Context, accountType: String, username: String, password: String) {
val accountManager = AccountManager.get(context)
val account = Account(username, accountType)
accountManager.addAccountExplicitly(account, password, null)
}
fun getCredentials(context: Context, accountType: String, username: String): String? {
val accountManager = AccountManager.get(context)
val accounts = accountManager.getAccountsByType(accountType)
for (account in accounts) {
if (account.name == username) {
return accountManager.getPassword(account)
}
}
return null
}
import Foundation
func saveCredentials(username: String, password: String) {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: username,
kSecValueData as String: password.data(using: .utf8)!,
kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked
]
SecItemDelete(query as CFDictionary)
SecItemAdd(query as CFDictionary, nil)
}
func getCredentials(username: String) -> String? {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: username,
kSecReturnData as String: true,
kSecMatchLimit as String: kSecMatchLimitOne
]
var dataTypeRef: AnyObject?
let status = SecItemCopyMatching(query as CFDictionary, &dataTypeRef)
guard status == errSecSuccess, let data = dataTypeRef as? Data else {
return nil
}
return String(data: data, encoding: .utf8)
}
import 'package:flutter/services.dart';
class CredentialService {
static const platform = MethodChannel('credentialChannel');
static Future<void> saveCredentials(String username, String password) async {
try {
await platform.invokeMethod('saveCredentials', {'username': username, 'password': password});
} on PlatformException catch (e) {
print("Failed to save credentials: '${e.message}'.");
}
}
static Future<String?> getCredentials(String username) async {
try {
return await platform.invokeMethod('getCredentials', {'username': username});
} on PlatformException catch (e) {
print("Failed to get credentials: '${e.message}'.");
return null;
}
}
}
Links
- OWASP Insecure Cryptographic Storage
- OWASP Insecure Storage
- CWE-522 Insufficiently Protected Credentials
- CWE-312 Cleartext Storage of Sensitive Information
- CWE-256 Plaintext Storage of a Password
Standards
- OWASP_MASVS_L1:
- MSTG_STORAGE_2
- OWASP_MASVS_L2:
- MSTG_STORAGE_2
- PCI_STANDARDS:
- REQ_2_2
- REQ_3_6
- REQ_3_7
- REQ_6_2
- OWASP_MASVS_v2_1:
- MASVS_STORAGE_1
- MASVS_STORAGE_2
- SOC2_CONTROLS:
- CC_2_1
- CC_4_1
- CC_6_7
- CC_7_1
- CC_7_2
- CC_7_4
- CC_7_5