通过 Postman 进行 HMAC 身份验证

Posted

技术标签:

【中文标题】通过 Postman 进行 HMAC 身份验证【英文标题】:HMAC authentication via Postman 【发布时间】:2018-12-30 17:30:59 【问题描述】:

我正在使用一个示例来为 Web API 项目设置 HMAC 身份验证。原始示例源代码/项目可在此处获得:

http://bitoftech.net/2014/12/15/secure-asp-net-web-api-using-api-key-authentication-hmac-authentication/

我正在尝试让 Postman 在其预请求脚本中构造和发送 GET 请求。但是,请求总是以 401 失败,我不知道为什么。 Postman 预请求脚本:

var AppId = "4d53bce03ec34c0a911182d4c228ee6c";
var APIKey = "A93reRTUJHsCuQSHR+L3GxqOJyDmQpCgps102ciuabc=";
var requestURI = "http%3a%2f%2flocalhost%3a55441%2fapi%2fv1%2fdata";
var requestMethod = "GET";
var requestTimeStamp = "$timestamp";
var nonce = "1";
var requestContentBase64String = "";

var signatureRawData  = AppId + requestMethod + requestURI + requestTimeStamp +  nonce + requestContentBase64String; //check
var signature = CryptoJS.enc.Utf8.parse(signatureRawData);
var secretByteArray = CryptoJS.enc.Base64.parse(APIKey);
var signatureBytes = CryptoJS.HmacSHA256(signature,secretByteArray)

var requestSignatureBase64String = CryptoJS.enc.Base64.stringify(signatureBytes);
postman.setGlobalVariable("key", "amx " + AppId + ":" + requestSignatureBase64String + ":" + nonce + ":" + requestTimeStamp);

【问题讨论】:

【参考方案1】:

这是我在我的 Pre-Script 中使用的代码。它适用于任何查询 GET、PUT、POST、DELETE。

您需要更改 AppId 和 APIKey 值,并在最后一行调整环境变量“hmacKey”的名称。

function interpolate (value) 
    const Property = require('postman-collection');
    return Property.replaceSubstitutions(value, pm.variables.toObject());


var uuid = require('uuid');
var moment = require("moment")

var hmacPrefix = "hmac";
var AppId = "4d53bce03ec34c0a911182d4c228ee6c";
var APIKey = "A93reRTUJHsCuQSHR+L3GxqOJyDmQpCgps102ciuabc=";
var requestURI = encodeURIComponent(pm.environment.values.substitute(pm.request.url, null, false).toString().toLowerCase());
var requestMethod = pm.request.method;
var requestTimeStamp = moment(new Date().toUTCString()).valueOf() / 1000;
var nonce = uuid.v4();
var requestContentBase64String = "";
var bodyString = interpolate(pm.request.body.toString());

if (bodyString) 
    var md5 = CryptoJS.MD5(bodyString);
    requestContentBase64String = CryptoJS.enc.Base64.stringify(md5);


var signatureRawData  = AppId + requestMethod + requestURI + requestTimeStamp +  nonce + requestContentBase64String; //check
var signature = CryptoJS.enc.Utf8.parse(signatureRawData);
var secretByteArray = CryptoJS.enc.Base64.parse(APIKey);
var signatureBytes = CryptoJS.HmacSHA256(signature,secretByteArray);
var requestSignatureBase64String = CryptoJS.enc.Base64.stringify(signatureBytes);

var hmacKey = hmacPrefix + " " + AppId + ":" + requestSignatureBase64String + ":" + nonce + ":" + requestTimeStamp;
postman.setEnvironmentVariable("hmacKey", hmacKey);

【讨论】:

不错的脚本!我确实在让它工作时遇到了一些麻烦,结果证明 toLowerCase() 应该在编码之前完成。 var requestURI = encodeURIComponent(pm.environment.values.substitute(pm.request.url, null, false).getRaw().toLowerCase()); 所以在encodeURIComponent(...) 里面。我还有一个问题,当协议未明确包含在 url 中时,客户端会从服务器获得不同的签名。例如localhost:5000/api/endpoint 我总是在我的 URL 中包含协议,我正在运行不同的环境,如 Prod、Pre-Prod、UAT、Dev 和调试(带有端口号),它工作正常。也许我可以给你我的身份验证方法的 .net 实现,它是 Nuget 并且非常易于使用。还要确保 Postman 和您的 API 之间的密钥完全相同 很好 - 这非常有帮助【参考方案2】:

经过几天的测试,我发现了问题所在。它实际上与 Postman 提供的所有事物的变量占位符有关。在测试占位符 $timestamp 的面值时,它传递了一个有效值。当我剥离签名以仅从一个片段开始时,我已成功通过身份验证。当然,直到我把时间戳占位符放回去。

当我将占位符换成标题中传递的实际值时,它工作正常。我只能得出结论,一定有一些我看不到的额外字符。也许在邮递员方面创建签名时。该问题延伸到其他占位符,例如 $guid。

【讨论】:

以上是关于通过 Postman 进行 HMAC 身份验证的主要内容,如果未能解决你的问题,请参考以下文章

使用 Postman 和 JWT 进行 JHipster 身份验证

使用 Postman 进行 Django Rest Framework 令牌身份验证

如何在 RESTful WCF API 中实现 HMAC 身份验证

使用 System.Web.Http.ApiController + Postman 进行身份验证 - 没有遇到断点/不确定这是如何工作的

如何使用 Postman 对 Django REST 框架进行身份验证

使用 Postman 的服务帐户对 Google Cloud Storage JSON API 进行身份验证