【问题标题】:Postman: custom signing request with SHA256 and RSAPostman:使用 SHA256 和 RSA 的自定义签名请求
【发布时间】:2022-03-15 12:00:26
【问题描述】:

我编写了一个接口来使用 python 向内部可听 api 发出请求。每个 API 请求都需要使用 RSA SHA256 进行签名。

现在我想用 Postman 测试 API 的端点并使用预请求脚本功能。但我对javascript并不坚定。也许有人可以帮助我将以下 python 函数转换为 Postman 脚本:


def sign_request(
    request: httpx.Request, adp_token: str, private_key: str
) -> httpx.Request:
    """
    Helper function who creates a signed requests for authentication.

    :param request: The request to be signed
    :param adp_token: the token is obtained after register as device
    :param private_key: the rsa key obtained after register as device
    :returns: The signed request
    """
    method = request.method
    path = request.url.path
    query = request.url.query
    body = request.content.decode("utf-8")
    date = datetime.utcnow().isoformat("T") + "Z"

    if query:
        path += f"?{query}"

    data = f"{method}\n{path}\n{date}\n{body}\n{adp_token}"

    key = rsa.PrivateKey.load_pkcs1(private_key.encode())
    cipher = rsa.pkcs1.sign(data.encode(), key, "SHA-256")
    signed_encoded = base64.b64encode(cipher)

    signed_header = {
        "x-adp-token": adp_token,
        "x-adp-alg": "SHA256withRSA:1.0",
        "x-adp-signature": f"{signed_encoded.decode()}:{date}"
    }
    request.headers.update(signed_header)

    return request

我发现了如何获取请求方法和正文。我可以通过pm.request.url.getPathWithQuery() 获取路径和查询。要将标头添加到请求中,我使用pm.request.headers.add

但我不知道如何获取 isoformat 中的日期时间、连接字符串和签署数据。

【问题讨论】:

标签: javascript python postman sign


【解决方案1】:

我正在使用pm lib 运行它。感谢您的帮助。

唯一的问题是从 env var 获取包含换行符的私有证书会在这些代码 sig.init(privateKey); 中出现错误。我必须直接在预请求脚本中编写私有证书字符串。

这是我的脚本。

eval( pm.globals.get('pmlib_code') );
var CryptoJS = require("crypto-js");
var moment = require("moment");

const adpToken = pm.environment.get("adp-token")
// private-key loaded from env var doesn't work because of newlines in it; bugfix
const privateKey = pm.environment.get("private-key")
// use private-key in pre request script directly make use of newline correctly
const privateKey2 = "-----BEGIN RSA PRIVATE KEY-----\nMIIE...==\n-----END RSA PRIVATE KEY-----\n"


signRequest(pm.request, adpToken, privateKey);

function signRequest(request, adpToken, privateKey2) {
    const method = request.method;
    const path = request.url.getPathWithQuery();
    const body = request.body || "";
    const date = moment.utc().format();
    const data = `${method}\n${path}\n${date}\n${body}\n${adpToken}`;
    var sig = new pmlib.rs.KJUR.crypto.Signature({"alg": "SHA256withRSA"});
    sig.init(privateKey);
    var hash = sig.signString(data);
    const signedEncoded = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Hex.parse(hash));

    pm.request.headers.add({
        key: 'x-adp-token',
        value: adpToken
    });

    pm.request.headers.add({
        key: 'x-adp-alg',
        value: 'SHA256withRSA:1.0'
    });

    pm.request.headers.add({
        key: 'x-adp-signature',
        value: `${signedEncoded}:${date}`
    });
}

更新:

现在可以从 env var 读取设备证书。我不得不用const privateKey = pm.environment.get("private-key").replace(/\\n/g, "\n")替换const privateKey = pm.environment.get("private-key")

【讨论】:

    【解决方案2】:

    在 Postman 中进行此操作的问题是您只能使用 sandbox 中提供的那些包。因此,为此,您将 crypto-js 作为加密操作的唯一包助手。

    var CryptoJS = require("crypto-js");
    var moment = require("moment");
    
    signRequest(pm.request, "yourAdpToken", "yourPrivateKey")
    
    function signRequest(request, adpToken, privateKey) {
        const method = request.method;
        const path = request.url.getPathWithQuery();
        const body = request.body.raw;
        const date = moment.utc().format();
        const data = `${method}\n${path}\n${date}\n${body}\n${adpToken}`
        const hash = CryptoJS.HmacSHA256(data, privateKey);
        const signedEncoded = CryptoJS.enc.Base64.stringify(hash);
    
        pm.request.headers.add({
            key: 'x-adp-token',
            value: adpToken
        });
    
        pm.request.headers.add({
            key: 'x-adp-alg',
            value: 'SHA256withRSA:1.0'
        });
    
        pm.request.headers.add({
            key: 'x-adp-signature',
            value: `${CryptoJS.enc.Base64.parse(signedEncoded)}:${date}`
        });
    }
    

    将上述内容添加到预请求脚本中会将您想要的标头添加到请求中,如下所示:

    您可能需要更改编码部分,请查看encode options

    【讨论】:

    • 感谢您的回答。它有很大帮助。但是您使用 HS256 进行签名。但是请求需要用 RS256 签名。我已经阅读了很多关于 crypto-js 的内容,但没有发现任何关于支持 rsa 的内容。
    • 我找到了支持RS256的Postman lib。但我不知道如何使用它来签署我的data 字符串。我可以用keyObj = pmlib.rs.KEYUTIL.getKey(privateKey) 加载我的密钥,但如果我尝试用keyObj.sign(data, "SHA256") 签名,我遇到了“错误:”而没有任何进一步的信息
    • 尝试通过KEYUTIL.getKeyFromCSRPEM()KEYUTIL.getKeyFromPlainPrivatePKCS8PEM() 更改您的getKey 方法。另请注意,在examples 中,他们首先创建一个符号对象,然后在更新字符串并调用sign() 方法之前调用init()(分配密钥)方法
    猜你喜欢
    • 1970-01-01
    • 2023-03-10
    • 2017-06-22
    • 1970-01-01
    • 1970-01-01
    • 2019-04-24
    • 2018-06-14
    • 2017-07-30
    • 1970-01-01
    相关资源
    最近更新 更多