Saltar a contenido

Insecure password storage

Almacenamiento inseguro de contraseñas

Descripción

El almacenamiento inseguro de contraseñas podría conducir al compromiso de la cuenta. La vulnerabilidad es el resultado de almacenar la contraseña utilizando métodos inseguros que son susceptibles de acceso no autorizado o compromiso.

El siguiente ejemplo muestra el almacenamiento inseguro de credenciales de contraseña en cookies:

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

Recomendación

Para almacenar de forma segura las credenciales de la cuenta, considere las siguientes recomendaciones:

  • Para Android, utilice AccountManager para almacenar las credenciales de la cuenta.
  • Para iOS, utilice keychain para almacenar las credenciales de la cuenta.
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;
    }
  }
}

Enlaces

Estándares

  • 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