alipay / alipay-sdk-nodejs-all

支付宝开放平台 Alipay SDK for Node.js
https://docs.open.alipay.com/54/103419/
Other
408 stars 64 forks source link

checkNotifySign 真的可用吗? #30

Closed cncolder closed 5 years ago

cncolder commented 5 years ago

正式环境下, 各种尝试, 返回值永远都是 false.

默认配置传入 3 个参数: appId privateKey alipayPublicKey

做过以下尝试:

  1. 修改 signTypekeyType.
  2. 删除 postData 中的 sign_type.
  3. key 改为 camelCase.
  4. 使用英文 subject.
  5. 填写英文可选参数 body.

postData 如下:

{
    "gmt_create": "2019-05-15 10:51:20",
    "charset": "utf-8",
    "gmt_payment": "2019-05-15 10:51:30",
    "notify_time": "2019-05-15 10:54:03",
    "subject": "充值",
    "sign": "UcMKLbURJGhbOnS8rznkXB0oo9OD8U69RM9s8pJI3lj9aKGMdMqmcy2kSzTAmFdNGRLNCOR6Y3bkJEDy50yQzUCjWkT9XWEuvww0pS2kBCQHEJDhbpap85GdzcXMSyPxR0QK6bHOp1rIZLjAAxi6WTnoIgeQopha/BQQwme+fLYkW3CuQX7bkHEcHqjo2ybDYWIMawc1WhmVuh2IfrlgBk8SN/bgoDFErZyrpfxeeuBliGghjSHACwzQ5UDGEJYacv62EovzTjhcxOFRYNtZITKelSFIPzGZMSFmcxDtrl0VJrYaeFy7Ga/EWEE8lT4n+c5AY6jHFV5vsuMrBqkPcg==",
    "buyer_id": "2088002164762921",
    "invoice_amount": "0.01",
    "version": "1.0",
    "notify_id": "2019051500222105131062921023025563",
    "fund_bill_list": "[{\"amount\":\"0.01\",\"fundChannel\":\"ALIPAYACCOUNT\"}]",
    "notify_type": "trade_status_sync",
    "out_trade_no": "5cdb7e9357bb33765ad585a6",
    "total_amount": "0.01",
    "trade_status": "TRADE_SUCCESS",
    "trade_no": "2019051522001462921037601726",
    "auth_app_id": "2019051164518127",
    "receipt_amount": "0.01",
    "point_amount": "0.00",
    "app_id": "2019051164518127",
    "buyer_pay_amount": "0.01",
    "sign_type": "RSA2",
    "seller_id": "2088531212288547"
}

目前只能是采用 mapi 接口验证 notify_id 的单一方式来验证通知的真实性.

cncolder commented 5 years ago

贴在这里警示后来者!

  1. alipayPublicKey 是指支付宝公钥, 而非应用公钥
  2. 正式环境下需要在调用 checkNotifySign 之前删除 sign_type, 而 checkNotifySign 函数内部又需要根据 sign_type 判断验签类型, 所以你的应用密钥需要使用 'RSA2', 或者自己写 checkNotifySign 函数.
屏幕快照 2019-05-17 16 55 44
zqqq commented 5 years ago

@cncolder alipayPublicKey 是指支付宝公钥 说明里写的是清楚的,但是sdk的checkNotifySign 却是错的,他们居然没有测试。delete signArgs.sign_type; 加上这句就正常了。


    checkNotifySign(postData) {
        const signStr = postData.sign;
        const signType = postData.sign_type || 'RSA2';
        if (!this.config.alipayPublicKey || !signStr) {
            return false;
        }
        const signArgs = Object.assign({}, postData);
        // 除去sign 皆是待验签的参数。
        delete signArgs.sign;
        delete signArgs.sign_type; //这里是增加的。。。。。。。!!!!!!!

        const decodeSign = Object.keys(signArgs).sort().filter(val => val).map((key) => {
            let value = signArgs[key];
            if (Array.prototype.toString.call(value) !== '[object String]') {
                value = JSON.stringify(value);
            }
            return `${key}=${decodeURIComponent(value)}`;
        }).join('&');

        const verifier = crypto.createVerify(util_1.ALIPAY_ALGORITHM_MAPPING[signType]);
        verifier.update(decodeSign, 'utf8');
        return verifier.verify(this.config.alipayPublicKey, signStr, 'base64');
    }```
zqqq commented 5 years ago

@cncolder 我看了他们更新日志,本来是有这一行的,结果,他们更新 Fixed: 修复通知校验签名失败的时候删除了,然后就真的永远失败了。。真是有意思。。这么严谨的事,居然连测试都没有。

cncolder commented 5 years ago

@zqqq 据说是为了修复沙箱环境, 我没测试.

zqqq commented 5 years ago

@cncolder 我看了java的sdk 分getSignCheckContentV1 和 getSignCheckContentV2 看这个nodejs的是按v2来的。。估计文档哪里有写 版本区别吧。。



  public static String getSignCheckContentV1(Map<String, String> params) {
        if (params == null) {
            return null;
        }

        params.remove("sign");
        params.remove("sign_type");

        StringBuffer content = new StringBuffer();
        List<String> keys = new ArrayList<String>(params.keySet());
        Collections.sort(keys);

        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = params.get(key);
            content.append((i == 0 ? "" : "&") + key + "=" + value);
        }

        return content.toString();
    }

    public static String getSignCheckContentV2(Map<String, String> params) {
        if (params == null) {
            return null;
        }

        params.remove("sign");

        StringBuffer content = new StringBuffer();
        List<String> keys = new ArrayList<String>(params.keySet());
        Collections.sort(keys);

        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = params.get(key);
            content.append((i == 0 ? "" : "&") + key + "=" + value);
        }

        return content.toString();
    }
`
keminshu commented 5 years ago

这个问题也花了我一个小时多,这里需要修改sdk,把 sign_type 给 delete 掉就好了。 image

qqaimh commented 5 years ago

加上 delete signArgs.sign_type; //这里是增加的。。。。。。。!!!!!!! 终于输出为true了 可以更新版本了,也不能老是改SDK

tudou527 commented 5 years ago

https://github.com/alipay/alipay-sdk-nodejs/blob/178b4e8803c0ed9f3a6ca35fa55caae60b060e55/lib/alipay.ts#L418-L452