コンテンツにスキップ

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