跳转至

Insecure password storage

不安全的密码存储

描述

密码存储不安全可能导致帐户受损。该漏洞是由于使用容易受到未经授权的访问或妥协的不安全方法存储密码造成的。

以下示例显示了在 Cookie 中不安全地存储密码凭证:

response.addCookie(new Cookie("password", password));

建议

为了安全地存储帐户凭证,请考虑以下建议:

  • 对于 Android,使用 AccountManager 存储帐户凭证。
  • 对于 iOS,使用 keychain 存储帐户凭证。
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;
    }
  }
}

链接

标准

  • 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
  • CNIL_FOR_DEVELOPERS:
    • DEVELOPERS_4_1_2
  • HIPAA_CONTROLS:
    • SECURITY251
    • SECURITY212
    • SECURITY213