2023. 7. 31. 00:00ㆍASPNET/ASPNET 7
aspnet web api 의 기본적인 server 를 만들자.
아래를 참조해도 된다.
https://yogingang.tistory.com/404
Rest API Template 만들기 - EP 01 (Create , Swagger, Logging)
Create visual studio 2022 를 실행하고 Create a new project 를 선택한다. asp.net core web api 선택 Project name 정하기 Additional Information 설정 Create 하면 Project 가 생성된다. F5 를 누르면 실행 된다. 위와 같이 swagger
yogingang.tistory.com
JWT 을 이용한 인증 및 권한관리를 하는 경우 JWT 자체에 보안에 위험성이 몇가지 있다.
- expire 시간이 지나기 전까지 token 을 무효화 하기 힘들다.
- payload 자체는 암호화 되지 않기 때문에 보안이 필요한 data 를 전달하기는 힘들다.
- jwt 자체는 단순 base64 encoding 된 data 이며 얼마든지 위변조 가능하다
위한 같은 문제들 때문에 jwt 를 이용한 인증 및 권한 관리는 많은 보안문제를 일으킨다.
하지만 다른 대안을 찾기도 쉽지 않다. jwt 만큼 microservice 에 맞는 인증 방식을 찾기도 힘들다.
1 번을 완벽히 해결하는 방법은 사실 없다고 봐야 한다.
왜냐하면 token 의 무효화 여부를 알기 위해 server 상에 특정 storage에 jwt 정보를 저장하는 순간
해당 server 로의 부하가 집중될 것이고 이것은 microservice 의 병목 지점이 될것이다.
그외에 문제들은 JWE(JSON Web Encryption), JWS (JSON Web Signature) 를 활용하여 해결한다.
이번 시간에는 aspnet core 에서 JWT 토큰을 생성할때 위 두가지를 이용하는 방법을 알아볼 것이다.
우선 jwt 관련 여러가지 helper method 들이 존재하는 다음 package 를 설치하자.
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
그리고 payload encryption, decryption 을 위한 비대칭키 알고리즘으로 RSA 를 이용하자
그리고 서명과 서명확인을 위해 curved 비대칭키 알고리즘인 ECDsa 를 이용하자
세부적인 bit 라든지 algorithm 은 직접 customizing 해도 된다.
한번 생성하여 재상용할 것이는 static class Helper 를 사용하여 활용하자
public static class JweTokenConfigHelper
{
private static RSA _encryptionKey = RSA.Create(3072); // public key for encryption, private key for decryption
private static ECDsa? _signingKey = ECDsa.Create(ECCurve.NamedCurves.nistP256); // private key for signing, public key for validation
private static string _encryptionKid = "8524e3e6674e494f85c5c775dcd602c5";
private static string _signingKid = "29b4adf8bcc941dc8ce40a6d0227b6d3";
public static RsaSecurityKey PrivateEncryptionKey = new RsaSecurityKey(_encryptionKey) { KeyId = _encryptionKid };
public static RsaSecurityKey PublicEncryptionKey = new RsaSecurityKey(_encryptionKey.ExportParameters(false)) { KeyId = _encryptionKid };
public static ECDsaSecurityKey PrivateSigningKey = new ECDsaSecurityKey(_signingKey) { KeyId = _signingKid };
public static ECDsaSecurityKey PublicSigningKey = new ECDsaSecurityKey(ECDsa.Create(_signingKey.ExportParameters(false))) { KeyId = _signingKid };
}
이제 이 정보들을 이용하여 JWT 를 생성해 보자
private string GenerateJweToken(string id)
{
var privateSigningKey = JweTokenConfigHelper.PrivateSigningKey;
var publicEncryptionKey = JweTokenConfigHelper.PublicEncryptionKey;
// JwtSecurityTokenHandler 의 향상된 버전 JsonWebTokenHandler
var handler = new JsonWebTokenHandler();
string token = handler.CreateToken(new SecurityTokenDescriptor
{
Audience = "IdentityServer",
Issuer = "https://localhost:7172",
Claims = new Dictionary<string, object> { { "sub", id } },
// private key for signing
SigningCredentials = new SigningCredentials(
privateSigningKey,
SecurityAlgorithms.EcdsaSha256),
// public key for encryption
EncryptingCredentials = new EncryptingCredentials(
publicEncryptionKey,
SecurityAlgorithms.RsaOAEP,
SecurityAlgorithms.Aes256CbcHmacSha512),
Expires = DateTime.UtcNow.AddMinutes(10)
}); ;
return token;
}
자 이제 되었다.
이것을 이용하여 JWT 를 생성하고 그 값을 복사한 후 https://jwt.io/ 에 가서 붙혀넣기 해보자
잘못된 base64 encoding 이라고 나오고 오른쪽 에도 header 를 제외한 다른 내용은 보지 못할것이다.
이제 이 JWT 를 validation 하는 custom authorization handler 를 생성해보자
private bool ValidateJweToken(string token)
{
try
{
var handler = new JsonWebTokenHandler();
TokenValidationResult result = handler.ValidateToken
(token,
new TokenValidationParameters
{
ValidAudience = "IdentityServer",
ValidIssuer = "https://localhost:7172",
// public key for signing
IssuerSigningKey = JweTokenConfigHelper.PublicSigningKey,
// private key for encryption
TokenDecryptionKey = JweTokenConfigHelper.PrivateEncryptionKey
});
return result.IsValid;
}
catch (Exception ex)
{
_logger.LogError(ex, "ValidateJweToken error");
}
return false;
}
IssuerSigningKey 에 PublicSigningKey 를 준다. (privatekey 로 signing 했으니 publickey 로 validation 해야 한다.)
TokenDecryptionKey 에 PrivateEncryptionKey 를 준다. ( publickey 로 encryption 했으니 privatekey 로 decryption 해야한다.)
위와 같이 하고 CustomAuthorizationHandler 에 위 코드를 이용하여 validation check 하도록 한다.
그러면 정상 처리 되는 것을 확인 할 수 있을 것이다.
관련영상
'ASPNET > ASPNET 7' 카테고리의 다른 글
인증서버 - API Key Management (3) | 2023.08.07 |
---|---|
Rest API Template 만들기 - EP 10 (Refactoring - Features) (0) | 2023.01.19 |
Rest API Template 만들기 - EP 09 (UnitTest) (0) | 2023.01.16 |
Rest API Template 만들기 - EP 08 (DB 를 통해 AccessToken 및 RefreshToken 관리) (0) | 2023.01.12 |
Rest API Template 만들기 - EP 07 (EF Core - Migration and Update) (0) | 2023.01.09 |