Storing passwords and protecting sensitive data in ASP.NET Core (Identity, Data Protection)

ASP.NET Core Interview Q&A November 13, 2026 csharp

Passwords: hashing, not encryption.

csharp
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// ======================================================================
// Q: How do you store passwords and protect sensitive data?
//
// - Passwords: hashing, not encryption. A slow algorithm with a salt (PBKDF2,
//   bcrypt, Argon2). ASP.NET Core Identity already does this. Never MD5 or plain
//   SHA-256 on its own.
// - Even better: no passwords in our database at all. Login through an external
//   IdP (Entra ID, Entra External ID, Keycloak) with MFA.
// - In transit: TLS everywhere, HSTS. At rest: database encryption (TDE), and
//   for very sensitive columns Always Encrypted or application-level encryption.
// - Data Protection API for cookies and tokens in links (password reset,
//   unsubscribe). With multiple instances the keys must be shared.
// - PII in logs: never tokens, passwords or full card details. Redaction with
//   Microsoft.Extensions.Compliance.Redaction. GDPR: right to erasure and
//   retention policies.
// ======================================================================

// If you need your own hashing (without the whole of Identity)
var hasher = new PasswordHasher<User>();                       // PBKDF2 + salt, with a version in the hash
user.PasswordHash = hasher.HashPassword(user, password);

var result = hasher.VerifyHashedPassword(user, user.PasswordHash, attempt);
if (result == PasswordVerificationResult.SuccessRehashNeeded)  // old algorithm: rehash
    user.PasswordHash = hasher.HashPassword(user, attempt);

// Data Protection keys shared across all instances (otherwise cookies break after scale-out)
builder.Services.AddDataProtection()
    .PersistKeysToAzureBlobStorage(new Uri(cfg["DataProtection:BlobUri"]!), new DefaultAzureCredential())
    .ProtectKeysWithAzureKeyVault(new Uri(cfg["DataProtection:KeyUri"]!), new DefaultAzureCredential());