HMAC(해시 기반 메시지 인증 코드)는 비밀 키와 함께 해시 함수를 포함하는 메시지 인증 코드를 계산하는 메커니즘입니다. 이는 메시지의 무결성과 신뢰성을 확인하는 데 사용될 수 있습니다.
이 구현은 Amazon Web Services(AWS Signature V4)에서 사용하는 기본 인증 방법에서 큰 영감을 얻었습니다. 이 방법은 매우 잘 이해되어 있으며 이를 구현하는 많은 라이브러리가 있습니다. 이 인증 형식을 사용하려면 일반적으로 관리 인터페이스에서 생성되는 키 식별자와 비밀 키를 사용합니다.
HmacAuthentication은 ASP.NET Core 프로젝트에서 HMAC 인증을 지원하는 AuthenticationHandler
제공합니다.
용법:
appsettings.json
파일에서 HMAC 인증 클라이언트를 가져옵니다. HMAC 인증의 경우 액세스해야 하는 각 클라이언트에 AppId
및 ApiKey
필요합니다. var hmacAuthenticatedApps = this . Configuration
. GetSection ( " Authentication " )
. GetSection ( " HmacAuthenticatedApps " )
. Get < HmacAuthenticationClientConfiguration [ ] > ( )
. ToDictionary ( e => e . AppId , e => e . ApiKey ) ;
{
"Authentication" : {
"HmacAuthenticatedApps" : [
{
"AppId" : " <some-app-id> " ,
"ApiKey" : " <some-api-key> "
}
]
}
}
ConfigureServices
메서드의 Startup.cs
에서 HMAC 인증을 활성화합니다. services
. AddAuthentication ( o =>
{
o . DefaultScheme = HmacAuthenticationDefaults . AuthenticationScheme ;
} )
. AddHmacAuthentication ( HmacAuthenticationDefaults . AuthenticationScheme , " HMAC Authentication " , o =>
{
o . MaxRequestAgeInSeconds = HmacAuthenticationDefaults . MaxRequestAgeInSeconds ;
o . HmacAuthenticatedApps = hmacAuthenticatedApps ;
} ) ;
ConfigureServices
메서드의 Startup.cs
에 MemoryCache
(Microsoft.Extensions.Caching.Memory에서)를 추가합니다. MemoryCache
는 HMAC AuthenticationHandler
에서 재생 공격을 결정하는 데 사용됩니다. services . AddMemoryCache ( ) ;
Configure
메서드의 Startup.cs
에서 인증을 활성화합니다. app . UseAuthentication ( ) ;
[ Authorize ( AuthenticationSchemes = HmacAuthenticationDefaults . AuthenticationScheme ) ]
[ Route ( " api/[controller] " ) ]
public class HomeController : Controller
{
// ...
}
HmacAuthenticaion은 HTTP 요청에 HMAC 인증 헤더를 추가하기 위한 DelegatingHandler
도 제공합니다.
ApiKeyDelegatingHandler
사용하여 HttpClient
인스턴스를 인스턴스화합니다. 모든 요청에 대해 새 HttpClient
인스턴스를 생성하지 않는지 확인하세요(자세한 내용은 이 블로그 게시물 참조).
new HttpClient ( new ApiKeyDelegatingHandler ( appId , apiKey ) ) ;
또는 WebAPI 클라이언트가 다른 ASP.NET WebAPI(>= ASP.NET Core 2.1)인 경우 다음과 같이 Startup.cs
에 HttpClient
를 등록하세요.
services . AddTransient ( sp => new ApiKeyDelegatingHandler ( appId , apiKey ) ) ;
services
. AddHttpClient ( " HmacHttpClient " )
. AddHttpMessageHandler < ApiKeyDelegatingHandler > ( ) ;
API 키를 생성하려면 다음과 같은 간단한 콘솔 애플리케이션을 사용할 수 있습니다. 이 구현은 .NET Fiddle에서도 제공됩니다.
using System . Security . Cryptography ;
public class Program
{
public static void Main ( )
{
Console . WriteLine ( $" AppID: { Guid . NewGuid ( ) } or <some-speaking-name> " ) ;
Console . WriteLine ( $" ApiKey: { GenerateApiKey ( ) } " ) ;
}
private static string GenerateApiKey ( )
{
using ( var cryptoProvider = new RNGCryptoServiceProvider ( ) )
{
byte [ ] secretKeyByteArray = new byte [ 32 ] ; //256 bit
cryptoProvider . GetBytes ( secretKeyByteArray ) ;
return Convert . ToBase64String ( secretKeyByteArray ) ;
}
}
}
보안 위험의 가장 큰 원인은 일반적으로 인증 프로토콜이 아니라 해당 프로토콜 사용과 관련된 정책 및 절차에서 발견됩니다. 구현자는 이 모듈이 보안 요구 사항을 어떻게 해결하는지 평가하는 것이 좋습니다. 이 섹션에는 이 인증 프로토콜을 서버에 배포하기 전에 검토하고 이해해야 하는 보안 고려 사항의 불완전한 목록이 포함되어 있습니다. 사양에 제공되는 많은 보호 기능은 사용 여부와 사용 방법에 따라 달라집니다.
HmacAuthentication은 필요한 공유 자격 증명 집합을 얻거나 전송하기 위한 메커니즘을 제공하지 않습니다. HmacAuthentication 자격 증명을 얻는 데 사용되는 모든 메커니즘은 TLS와 같은 전송 계층 메커니즘을 사용하여 이러한 전송이 보호되도록 해야 합니다.
HmacAuthentication은 HTTP 요청의 무결성을 확인하는 메커니즘을 제공하지만 요청 기밀성을 보장하지는 않습니다. 다른 예방 조치를 취하지 않는 한, 도청자는 요청 내용에 대한 전체 액세스 권한을 갖게 됩니다. 서버는 그러한 요청의 일부로 전송될 수 있는 데이터 유형을 신중하게 고려해야 하며 전송 계층 보안 메커니즘을 사용하여 민감한 리소스를 보호해야 합니다.
HmacAuthentication은 서버 신뢰성에 대한 제한된 검증을 제공합니다. 서버로부터 응답을 받을 때.
적대적인 당사자는 클라이언트의 요청을 가로채서 오해의 소지가 있거나 잘못된 응답을 반환함으로써 이를 이용할 수 있습니다. 서비스 제공자는 이 프로토콜을 사용하여 서비스를 개발할 때 이러한 공격을 고려해야 하며 리소스 서버 또는 서버 응답의 신뢰성이 문제가 되는 모든 요청에 대해 전송 계층 보안을 요구해야 합니다.
HmacAuthentication 키는 기존 인증 시스템에서 비밀번호와 동일한 방식으로 작동합니다. 요청 MAC을 계산하려면 서버가 일반 텍스트 형식의 키에 액세스할 수 있어야 합니다. 예를 들어 이는 사용자 자격 증명의 단방향 해시만 저장하는 최신 운영 체제와는 대조적입니다.
공격자가 이러한 키에 액세스하거나 더 나쁘게는 이러한 모든 키가 포함된 서버 데이터베이스에 액세스할 수 있는 경우 공격자는 리소스 소유자를 대신하여 모든 작업을 수행할 수 있습니다. 따라서 서버가 이러한 키를 무단 액세스로부터 보호하는 것이 중요합니다.
전송 계층 보안 프로토콜을 사용하지 않는 한, 도청자는 인증된 요청 및 요청 MAC 값에 대한 전체 액세스 권한을 가지므로 오프라인 무차별 대입 공격을 실행하여 사용된 키를 복구할 수 있습니다. 서버는 최소한 HmacAuthentication 자격 증명이 유효한 기간 동안 이러한 공격에 저항할 수 있을 만큼 충분히 길고 무작위인 키를 할당하도록 주의해야 합니다.
예를 들어 자격 증명이 2주 동안 유효한 경우 서버는 2주 이내에 키를 복구하는 무차별 대입 공격이 불가능하도록 해야 합니다. 물론, 서버는 실수에 주의하고 합리적으로 가장 긴 키를 사용하도록 권장됩니다.
이러한 키를 생성하는 데 사용되는 PRNG(의사 난수 생성기)의 품질이 충분히 높은 것도 마찬가지로 중요합니다. 많은 PRNG 구현은 무작위로 보일 수 있는 숫자 시퀀스를 생성하지만 그럼에도 불구하고 암호 분석 또는 무차별 대입 공격을 더 쉽게 만드는 패턴이나 기타 약점을 나타냅니다. 구현자는 이러한 문제를 방지하기 위해 암호화된 보안 PRNG를 사용할 때 주의해야 합니다.
요청 MAC에는 HTTP Host
헤더, Content-Type
헤더 및 선택적으로 지정된 헤더 세트만 포함됩니다. 서버에서 요청 본문을 해석하는 방식에 영향을 미칠 수 있는 다른 헤더는 다루지 않습니다. 서버 동작이 그러한 헤더의 존재나 값에 의해 영향을 받는 경우 공격자는 탐지되지 않고 요청 헤더를 조작할 수 있습니다. 구현자는 headers
기능을 사용하여 요청 MAC에 의해 보호되는 Authorization
헤더를 통해 서명에 추가할 헤더를 전달해야 합니다. 그런 다음 서명 기본 문자열은 이러한 주어진 헤더를 서명에 추가하여 MAC의 일부가 되도록 합니다.
응답 인증이 수행되면 응답 본문(페이로드)과 타임스탬프 및 nonce와 같이 클라이언트가 요청에서 제공한 일부 요청 정보만 포함됩니다. 클라이언트의 동작에 영향을 미칠 수 있는 HTTP 상태 코드나 기타 응답 헤더 필드(예: 위치)는 다루지 않습니다.
공격자가 이 정보를 조작하여 클라이언트가 잘못된 시간을 사용하도록 만들 수 있는 경우 클라이언트가 미래의 시간을 사용하여 인증된 요청을 생성하도록 할 수 있습니다. 이러한 요청은 클라이언트가 보낼 때 실패하며 서버에 추적을 남기지 않을 가능성이 높습니다(전혀 시행되는 경우 nonce의 일반적인 구현을 고려할 때). 그러면 공격자는 탐지되지 않고 정확한 시간에 요청을 재생할 수 있습니다.
이 문제에 대한 해결책은 클라이언트와 서버 간의 시계 동기화입니다. 이를 달성하기 위해 서버는 유효하지 않은 타임스탬프가 수신되면 클라이언트에게 현재 시간을 알립니다. 이는 응답의 Date 헤더 형식으로 발생합니다. 이에 대한 동기는 RFC2616을 참조하십시오.
클라이언트는 다음과 같은 경우에만 서버에서 제공하는 시간 정보를 사용해야 합니다.
타임스탬프가 잘못된 요청을 받으면 서버는 클라이언트에 현재 시간을 제공합니다. 클라이언트는 서버로부터 받은 시간을 자신의 시계를 조정하는 데 사용해서는 안 되며, 특정 서버와 통신하기 위한 오프셋을 계산하는 데만 사용해야 합니다.
HmacAuthentication은 들어오는 HTTP 호스트 헤더에 대해 들어오는 요청 MAC의 유효성을 검사합니다. 악의적인 클라이언트는 서버의 IP 주소를 가리키는 새 호스트 이름을 생성하고 이를 사용하여 서버에서 사용하는 호스트 이름이 아닌 다른 호스트 이름에 대한 유효한 요청을 보내 공격을 만들 수 있습니다. 서버 구현자는 수신된 호스트 헤더가 예상과 일치하는지 수동으로 확인해야 합니다. 예를 들어 test.myapi.com에서 API 호출이 예상되는 경우 서버 구현에서 요청이 전송된 도메인인지 확인하세요.