Data Protection provider across Asp.NET Core and Framework (generate password reset link)

假如想象 提交于 2019-12-01 15:55:07

The Data Protection API will work the same in .NET Framework and .NET Core.

Instead of a machine key, encrypt the keys with an X509 certificate rather than the old machine-key approach. A self-generated certificate is fine since the encryption is purely for internal use.

Important: If you control the servers, the certificate must be installed in the certificate store. There's a ridiculous, undocumented catch to using the ProtectWithCertificate overloads that accept an X509 certificate instance: it can only use that instance to encrypt. Decryption fails if the cert isn't in the store. Microsoft claims this is some limitation of "the underlying framework," whatever that means, but workarounds are available (and not complicated). I use a variation on this and the cert is serialized to Azure Key Vault so that we don't have to touch each individual server.

You also need to specify one of the DPAPI persistence options to ensure the data is accessible to all the servers. Since we're using Azure, my code below uses blob storage, but if you're running your own servers, this could be a network share via PersistKeysToFileSystem.

My setup in ConfigureServices looks like this:

var x509 = GetDpApiCert(); // library utility
var container = GetBlobStorageRef(); // library

services.AddDataProtection()
    .SetApplicationName(appconfig["DpapiSiteName"])
    .ProtectKeysWithProvidedCertificate(x509)
    .PersistKeysToAzureBlobStorage(container, appconfig["DpapiFileName"]);

Here's my Powershell script to generate a certificate:

[CmdletBinding()]
param(
    [Parameter(Mandatory=$true)][string]$password = "",
    [Parameter(Mandatory=$true)][string]$rootDomain = ""
)

$cwd = Convert-Path .
$CerFile = "$cwd\aspnet_dpapi.cer"
$PfxFile = "$cwd\aspnet_dpapi.pfx"

# abort if files exist
if((Test-Path($PfxFile)) -or (Test-Path($CerFile)))
{
    Write-Warning "Failed, aspnet_dpapi already exists in $cwd"
    Exit
}

$cert = New-SelfSignedCertificate `
        -Subject $rootDomain `
        -DnsName $rootDomain `
        -FriendlyName "ASP.NET Data Protection $rootDomain" `
        -NotBefore (Get-Date) `
        -NotAfter (Get-Date).AddYears(10) `
        -CertStoreLocation "cert:CurrentUser\My" `
        -KeyAlgorithm RSA `
        -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" `
        -KeyLength 2048 `
        -KeyUsage KeyEncipherment, DataEncipherment
        # -HashAlgorithm SHA256 `
        # -Type Custom,DocumentEncryptionCert `
        # -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.1")

$store = 'Cert:\CurrentUser\My\' + ($cert.ThumbPrint)  
$securePass = ConvertTo-SecureString -String $password -Force -AsPlainText

Export-Certificate -Cert $store -FilePath $CerFile
Export-PfxCertificate -Cert $store -FilePath $PfxFile -Password $securePass
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!