.NET 6.0 Web API의 클라이언트 인증서 인증
요약
이 기사에서는 클라이언트 인증서 인증을 지원하는 .NET 6.0 Web API 샘플 코드를 공유합니다. The sample code은 전송 계층 보안 프로토콜(RFC5246)에 작성된 핸드셰이크 프로토콜의 인증서 요청과 유사한 .NETMicrosoft.AspNetCore.Authentication.Certificate
의 내장 기능을 활용합니다.
목차
Concept
개념
- Web Server requires a client certificate and validate the certificate is trusted during TLS handshake.
-
CertificateAuthenticationOptions
handler checks the certificate type.
-
CertificateValidationService
validates the pfx file or thumbprint.
- Controller has to have
[Authorize]
attribute because it deals with the context determined in TLS handshake and Authentication/Authorization middleware.
웹 서버 - 로컬 컴퓨터(Kestrel)
- Configure Kestrel server for a local run so it requires a client certificate during TLS handshake
-
Microsoft.AspNetCore.Server.Kestrel.Https.ClientCertificateMode
has options such as RequireCertificate
and AllowCertificate
. Once you set RequireCertificate
, any request without a client certificate is declined.
- A self-signed certificate does not work without
AllowAnyClientCertificate()
method.
Program.cs
builder.Services.Configure<KestrelServerOptions>(options =>
{
options.ConfigureHttpsDefaults(options =>
{
options.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
options.AllowAnyClientCertificate();
});
});
웹 서버 - Azure 앱 서비스
- When the application code is deployed in Azure App Service, it requires another Web Server configuration than Kestrel in
Program.cs
.
- Azure App Service has configuration that accepts and requires a client certificate in the request from the client application.
- Set
clientCertEnabled: true
and clientCertMode: 'Required'
in your bicep file.
- It looks you do not need to specify self-signed certificate for Azure App Service.
Bicep example
resource AppServiceCert 'Microsoft.Web/sites@2021-03-01' = {
name: appsrv_name_cert
location: location
kind: 'app'
identity: {
type: 'SystemAssigned'
}
properties: {
serverFarmId: AppServicePlanCert.id
httpsOnly: true
clientCertEnabled: true
clientCertMode: 'Required'
siteConfig: {
netFrameworkVersion: '6.0'
http20Enabled: true
minTlsVersion: '1.2'
}
}
}
인증 이벤트
- An event handler
CertificateAuthenticationEvents
is triggered during a TLS handshake, which is written with builder.Services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
in Program.cs
.
- A self-signed certificate requires
CertificateAuthenticationOptions.AllowedCertificateTypes
property to be All
or SelfSigned
.
- The
CertificateAuthenticationOptions
handler calls CertificateValidationService
and set the context success or fail.
- If the validation fails, it returns 403 forbidden during the TLS handshake before it reaches .NET application.
Program.cs
builder.Services.AddAuthentication(
CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate(options =>
{
options.AllowedCertificateTypes = CertificateTypes.All;
options.Events = new CertificateAuthenticationEvents
{
OnCertificateValidated = context =>
{
var validationService = context.HttpContext.RequestServices
.GetRequiredService<ICertificateValidationService>();
if (validationService.ValidateCertificate(context.ClientCertificate))
{
context.Success();
}
else
{
context.Fail("Invalid certificate");
}
return Task.CompletedTask;
}
};
});
인증서 유효성 검사
-
CertificateValidationService
handles the certificate validation and returns true/false to CertificateAuthenticationOptions
handler.
- To validate an incoming client certificate, the Web API app config has Pfx file path and Pfx password, or the certificate thumbprint.
- If the Web API instance does not have the Pfx file, for example, if it is deployed in Azure App Service, the service validates if the incoming certificate thumbprint is identical with the one in the app config.
CertificateValidationService
public bool ValidateCertificate(X509Certificate2 clientCertificate)
{
X509Certificate2 expectedCertificate;
string pfxFilePath = this.configuration.GetValue<string>("Certificate:PfxFilePath");
string pfxFilePassword = this.configuration.GetValue<string>("Certificate:PfxFilePassword");
if (File.Exists(Path.Combine(Directory.GetCurrentDirectory(), pfxFilePath)))
{
expectedCertificate = new X509Certificate2(
Path.Combine(Directory.GetCurrentDirectory(), pfxFilePath), pfxFilePassword);
return clientCertificate.Thumbprint == expectedCertificate.Thumbprint;
}
else
{
return clientCertificate.Thumbprint == this.configuration.GetValue<string>("Certificate:Thumbprint");
}
}
구성 - 로컬 머신
For local run, you will set the Pfx file path and password or thumbprint in appsettings.json
or appsettings.Development.json
appsettings.json 예시
"Certificate": {
"PfxFilePath": "certificates/sample.pfx",
"PfxFilePassword": "{Pfx file password if needed}",
"Thumbprint": "6B132..."
}
구성 - Azure 앱 서비스
- It is difficult to have the Pfx file in Azure App Service, and then it can validate with the thumbprint.
- The thumbprint should be stored in Azure Key Vault and the App Service extracts it through Key Vault reference.
Bicep example
resource AppServiceConfigCert 'Microsoft.Web/sites/config@2021-03-01' = {
name: '${AppServiceCert.name}/appsettings'
properties: {
'Certificate:PfxFilePath': ''
'Certificate:PfxFilePassword': ''
'Certificate:Thumbprint': '@Microsoft.KeyVault(VaultName=${kv_name};SecretName=${kvsecret_name_cert_thumbprint})'
'WEBSITE_RUN_FROM_PACKAGE': 1
}
}
샘플 요청
- It seems bash does not have a feature to send a pfx file. So I tried with a cert file and private key.
- Powershell supports sending a pfx file. It requires a password after calling
Invoke-RestMethod
, if needed.
Bash
curl {App URL}/Weatherforecast/RequireAuth \
--cert ./sample.crt \
--key ./sample.key \
--insecure
Powershell
$parameters = @{
Method = 'GET'
Uri = '{App URL}/Weatherforecast/RequireAuth'
Certificate = (Get-PfxCertificate '.\sample.pfx')
}
Invoke-RestMethod @parameters
자체 서명된 인증서
Here is just my note of how to generate a self-signed certificate with openssl.
PEM
DER
PKCS#12
Data format
Base64 ASCII
Binary
Binary
Extension
.cer .pem .crt .key
.cer .der
.pfx .p12
개인 키: sample.key
공개 키: sample_public.key
인증서 서명 요청: sample.csr
인증서(PEM): sample.crt
인증서(PKCS#12): sample.pfx
개인 키 만들기
openssl genrsa -out sample.key 2048
개인 키에서 공개 키 만들기
openssl rsa -in sample.key -pubout -out sample_public.key
CSR 만들기
openssl req -new -key sample.key -out sample.csr
인증서 생성(PEM)
openssl x509 -signkey sample.key -in sample.csr -req -days 365 -out sample.crt
인증서 생성(PKCS#12)
openssl pkcs12 -export -inkey sample.key -in sample.crt -out sample.pfx
Reference
이 문제에 관하여(.NET 6.0 Web API의 클라이언트 인증서 인증), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/koheikawata/client-certifiate-authenticaiton-of-net-60-web-api-i9i
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
CertificateAuthenticationOptions
handler checks the certificate type.CertificateValidationService
validates the pfx file or thumbprint.[Authorize]
attribute because it deals with the context determined in TLS handshake and Authentication/Authorization middleware.Microsoft.AspNetCore.Server.Kestrel.Https.ClientCertificateMode
has options such as RequireCertificate
and AllowCertificate
. Once you set RequireCertificate
, any request without a client certificate is declined.AllowAnyClientCertificate()
method.builder.Services.Configure<KestrelServerOptions>(options =>
{
options.ConfigureHttpsDefaults(options =>
{
options.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
options.AllowAnyClientCertificate();
});
});
Program.cs
.clientCertEnabled: true
and clientCertMode: 'Required'
in your bicep file.resource AppServiceCert 'Microsoft.Web/sites@2021-03-01' = {
name: appsrv_name_cert
location: location
kind: 'app'
identity: {
type: 'SystemAssigned'
}
properties: {
serverFarmId: AppServicePlanCert.id
httpsOnly: true
clientCertEnabled: true
clientCertMode: 'Required'
siteConfig: {
netFrameworkVersion: '6.0'
http20Enabled: true
minTlsVersion: '1.2'
}
}
}
CertificateAuthenticationEvents
is triggered during a TLS handshake, which is written with builder.Services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
in Program.cs
.CertificateAuthenticationOptions.AllowedCertificateTypes
property to be All
or SelfSigned
.CertificateAuthenticationOptions
handler calls CertificateValidationService
and set the context success or fail.builder.Services.AddAuthentication(
CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate(options =>
{
options.AllowedCertificateTypes = CertificateTypes.All;
options.Events = new CertificateAuthenticationEvents
{
OnCertificateValidated = context =>
{
var validationService = context.HttpContext.RequestServices
.GetRequiredService<ICertificateValidationService>();
if (validationService.ValidateCertificate(context.ClientCertificate))
{
context.Success();
}
else
{
context.Fail("Invalid certificate");
}
return Task.CompletedTask;
}
};
});
CertificateValidationService
handles the certificate validation and returns true/false to CertificateAuthenticationOptions
handler.public bool ValidateCertificate(X509Certificate2 clientCertificate)
{
X509Certificate2 expectedCertificate;
string pfxFilePath = this.configuration.GetValue<string>("Certificate:PfxFilePath");
string pfxFilePassword = this.configuration.GetValue<string>("Certificate:PfxFilePassword");
if (File.Exists(Path.Combine(Directory.GetCurrentDirectory(), pfxFilePath)))
{
expectedCertificate = new X509Certificate2(
Path.Combine(Directory.GetCurrentDirectory(), pfxFilePath), pfxFilePassword);
return clientCertificate.Thumbprint == expectedCertificate.Thumbprint;
}
else
{
return clientCertificate.Thumbprint == this.configuration.GetValue<string>("Certificate:Thumbprint");
}
}
appsettings.json
or appsettings.Development.json
"Certificate": {
"PfxFilePath": "certificates/sample.pfx",
"PfxFilePassword": "{Pfx file password if needed}",
"Thumbprint": "6B132..."
}
resource AppServiceConfigCert 'Microsoft.Web/sites/config@2021-03-01' = {
name: '${AppServiceCert.name}/appsettings'
properties: {
'Certificate:PfxFilePath': ''
'Certificate:PfxFilePassword': ''
'Certificate:Thumbprint': '@Microsoft.KeyVault(VaultName=${kv_name};SecretName=${kvsecret_name_cert_thumbprint})'
'WEBSITE_RUN_FROM_PACKAGE': 1
}
}
- It seems bash does not have a feature to send a pfx file. So I tried with a cert file and private key.
- Powershell supports sending a pfx file. It requires a password after calling
Invoke-RestMethod
, if needed.
Bash
curl {App URL}/Weatherforecast/RequireAuth \
--cert ./sample.crt \
--key ./sample.key \
--insecure
Powershell
$parameters = @{
Method = 'GET'
Uri = '{App URL}/Weatherforecast/RequireAuth'
Certificate = (Get-PfxCertificate '.\sample.pfx')
}
Invoke-RestMethod @parameters
자체 서명된 인증서
Here is just my note of how to generate a self-signed certificate with openssl.
PEM
DER
PKCS#12
Data format
Base64 ASCII
Binary
Binary
Extension
.cer .pem .crt .key
.cer .der
.pfx .p12
개인 키: sample.key
공개 키: sample_public.key
인증서 서명 요청: sample.csr
인증서(PEM): sample.crt
인증서(PKCS#12): sample.pfx
개인 키 만들기
openssl genrsa -out sample.key 2048
개인 키에서 공개 키 만들기
openssl rsa -in sample.key -pubout -out sample_public.key
CSR 만들기
openssl req -new -key sample.key -out sample.csr
인증서 생성(PEM)
openssl x509 -signkey sample.key -in sample.csr -req -days 365 -out sample.crt
인증서 생성(PKCS#12)
openssl pkcs12 -export -inkey sample.key -in sample.crt -out sample.pfx
Reference
이 문제에 관하여(.NET 6.0 Web API의 클라이언트 인증서 인증), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/koheikawata/client-certifiate-authenticaiton-of-net-60-web-api-i9i
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
PEM | DER | PKCS#12 | |
---|---|---|---|
Data format | Base64 ASCII | Binary | Binary |
Extension | .cer .pem .crt .key | .cer .der | .pfx .p12 |
openssl genrsa -out sample.key 2048
openssl rsa -in sample.key -pubout -out sample_public.key
openssl req -new -key sample.key -out sample.csr
openssl x509 -signkey sample.key -in sample.csr -req -days 365 -out sample.crt
openssl pkcs12 -export -inkey sample.key -in sample.crt -out sample.pfx
Reference
이 문제에 관하여(.NET 6.0 Web API의 클라이언트 인증서 인증), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/koheikawata/client-certifiate-authenticaiton-of-net-60-web-api-i9i텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)