基于散列的消息认证码(HMAC)是一种用于计算消息认证码的机制,涉及散列函数与密钥的结合。这可以用来验证消息的完整性和真实性。
此实现深受 Amazon Web Services (AWS Signature V4) 使用的主要身份验证方法的启发,因为它非常容易理解,并且有许多库实现它。要使用这种形式的身份验证,您需要使用密钥标识符和密钥,这两个密钥通常在管理界面中生成。
HmacAuthentication提供了一个AuthenticationHandler
,它支持 ASP.NET Core 项目中的 HMAC 身份验证。
用法:
appsettings.json
文件中获取。对于 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> "
}
]
}
}
Startup.cs
的ConfigureServices
方法中启用HMAC身份验证: services
. AddAuthentication ( o =>
{
o . DefaultScheme = HmacAuthenticationDefaults . AuthenticationScheme ;
} )
. AddHmacAuthentication ( HmacAuthenticationDefaults . AuthenticationScheme , " HMAC Authentication " , o =>
{
o . MaxRequestAgeInSeconds = HmacAuthenticationDefaults . MaxRequestAgeInSeconds ;
o . HmacAuthenticatedApps = hmacAuthenticatedApps ;
} ) ;
Startup.cs
的ConfigureServices
方法中添加MemoryCache
(来自Microsoft.Extensions.Caching.Memory)。 HMAC AuthenticationHandler
使用MemoryCache
来确定重放攻击。 services . AddMemoryCache ( ) ;
Startup.cs
的Configure
方法中启用身份验证: app . UseAuthentication ( ) ;
[ Authorize ( AuthenticationSchemes = HmacAuthenticationDefaults . AuthenticationScheme ) ]
[ Route ( " api/[controller] " ) ]
public class HomeController : Controller
{
// ...
}
HmacAuthenticaion还提供DelegatingHandler
,用于将 HMAC 授权标头添加到 HTTP 请求。
使用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 ) ;
}
}
}
安全风险的最大来源通常不是在身份验证协议中,而是在围绕其使用的策略和程序中。强烈鼓励实施者评估该模块如何满足他们的安全要求。本节包含安全注意事项的不完整列表,在服务器上部署此 Auth 协议之前必须查看和理解这些注意事项。规范中提供的许多保护措施取决于是否使用以及如何使用。
HmacAuthentication不提供任何机制来获取或传输所需的共享凭据集。用于获取HmacAuthentication凭据的任何机制都必须确保使用传输层机制(例如 TLS)保护这些传输。
虽然HmacAuthentication提供了一种验证 HTTP 请求完整性的机制,但它不提供请求机密性的保证。除非采取其他预防措施,否则窃听者将能够完全访问请求内容。服务器应仔细考虑可能作为此类请求的一部分发送的数据类型,并采用传输层安全机制来保护敏感资源。
HmacAuthentication提供对服务器真实性的有限验证。当收到服务器返回的响应时。
敌对方可以通过拦截客户端的请求并返回误导性或其他不正确的响应来利用这一点。服务提供商在使用此协议开发服务时应考虑此类攻击,并且对于资源服务器或服务器响应的真实性存在问题的任何请求,应要求传输层安全。
HmacAuthentication密钥的功能与传统身份验证系统中的密码相同。为了计算请求 MAC,服务器必须能够访问明文形式的密钥。例如,这与现代操作系统形成鲜明对比,现代操作系统仅存储用户凭据的单向哈希值。
如果攻击者获得对这些密钥的访问权限,或者更糟糕的是,获得所有此类密钥的服务器数据库的访问权限,他或她将能够代表任何资源所有者执行任何操作。因此,服务器保护这些密钥免遭未经授权的访问至关重要。
除非使用传输层安全协议,否则窃听者将能够完全访问经过身份验证的请求和请求 MAC 值,因此能够发起离线强力攻击以恢复所使用的密钥。服务器应小心分配足够长且足够随机的密钥,以至少在HmacAuthentication凭据有效的时间内抵御此类攻击。
例如,如果凭证的有效期为两周,服务器应确保不可能发起在不到两周内恢复密钥的暴力攻击。当然,我们建议服务器谨慎行事,并合理使用最长的密钥。
同样重要的是,用于生成这些密钥的伪随机数生成器 (PRNG) 必须具有足够高的质量。许多 PRNG 实现生成的数字序列可能看起来是随机的,但它们仍然表现出模式或其他弱点,使密码分析或暴力攻击变得更容易。实施者应谨慎使用加密安全的 PRNG 以避免这些问题。
请求 MAC 仅涵盖 HTTP Host
标头、 Content-Type
标头以及可选的一组给定标头。它不涵盖它不知道的任何其他标头,这些标头通常会影响服务器解释请求正文的方式。如果服务器行为受到此类标头的存在或值的影响,则攻击者可以在不被发现的情况下操纵请求标头。实施者应使用headers
功能通过受请求 MAC 保护的Authorization
标头来传递要添加到签名的标头。然后,签名基字符串将负责将这些给定标头添加到签名中,以便它们成为 MAC 的一部分。
执行响应身份验证时,仅涵盖响应正文(有效负载)和客户端在其请求中提供的一些请求信息,例如时间戳和随机数。它不包括 HTTP 状态代码或任何其他可能影响客户端行为的响应标头字段(例如位置)。
如果攻击者能够操纵此信息并导致客户端使用不正确的时间,则将能够导致客户端将来使用时间生成经过身份验证的请求。当客户端发送此类请求时,此类请求将失败,并且不太可能在服务器上留下痕迹(考虑到随机数的常见实现,如果强制执行的话)。然后,攻击者将能够在正确的时间重播请求而不被检测到。
此问题的解决方案是客户端和服务器之间的时钟同步。为了实现这一点,服务器在收到无效时间戳时通知客户端其当前时间。这以响应中的日期标头的形式发生。请参阅 RFC2616 作为其动机。
客户端应仅在以下情况下使用服务器提供的时间信息:
当收到带有错误时间戳的请求时,服务器会向客户端提供当前时间。客户端绝不能使用从服务器接收到的时间来调整自己的时钟,而只能使用它来计算与该特定服务器通信的偏移量。
HmacAuthentication根据传入的 HTTP 主机标头验证传入请求的 MAC。恶意客户端可以创建指向服务器 IP 地址的新主机名,并通过发送针对服务器所使用的主机名之外的另一个主机名的有效请求来利用该主机名进行攻击。服务器实现者必须手动验证收到的主机标头是否符合他们的期望。例如,如果您期望在 test.myapi.com 上进行 API 调用,请验证该域是否是服务器实现中请求发送到的域。