首页 > 编程 > PHP > 正文

PHP支付宝接口RSA验证

2020-03-22 18:44:16
字体:
来源:转载
供稿:网友
  • 这两天一直困扰的PHP RSA签名验证问题终于解决了,由于之前RSA接触的不多,再加上官方至今还未有PHP的SDK可供参考,因此走了一些弯路,写在这里和大家分享。
    虽然支付宝官方还未提供相关SDK,PHP确实可以实现RSA方式的签名,这点其实很重要,由于不熟悉,在遇到困难的时候,经常会不由自主地想到是否PHP不支持RSA签名,干脆用MD5得了,这样就没有了前进的动力。其实说穿了MD5和RSA签名,不同的只是签名方式的区别,其他的都一样,因此我这里主要说一下如何用RSA进行签名和验签。

    首先你需要准备下面的东西:
    php的openssl扩展里已经封装好了验签的方法openssl_verify。 如果在Windows下的php.ini需要开启Openssl模块:extension=php_openssl.dll

    商户私钥:

    即RSA私钥,按照手册,按以下方式生成:

    openssl genrsa -out rsa_private_key.pem 1024

    商户公钥:

    即RSA私钥,按照手册,按以下方式生成:
    openssl rsa -in rsa_private_key.pem -pubout -out rsa_html' target='_blank'>public_key.pem

    生成之后,按照手册的说明,需要在签约平台上传公钥,需要注意的是,上传的时候需要把所有的注释和换行都去掉。

    另外手册中还有如下命令:

    openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt

    该命令将RSA私钥转换成PKCS8格式,对于PHP来说,不需要。

    支付宝公钥:

    根据手册,在签约平台获得。
    如果你直接复制下来的话,会得到一个字符串,需要进行下面的转换;
    1)把空格变成换行
    2)添加注释
    比如你复制下来的公钥是:MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRBMjkaBznjXk06ddsL751KyYt

    ztPFg0D3tu7jLqCacgqL+lbshIaItDGEXAMZmKa3DV6Wxy+l48YMo0RyS+dWze4M UmuxHU/v6tiT0ZTXJN3EwrjCtCyyttdv/ROB3CkheXnTKB76reTkQqg57OWW+m9j

    TCoccYMDXEIWYTs3CwIDAQAB,那转换之后为:
    -----BEGIN PUBLIC KEY-----

    MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRBMjkaBznjXk06ddsL751KyYt ztPFg0D3tu7jLqCacgqL+lbshIaItDGEXAMZmKa3DV6Wxy+l48YMo0RyS+dWze4M UmuxHU/v6tiT0ZTXJN3EwrjCtCyyttdv/ROB3CkheXnTKB76reTkQqg57OWW+m9j TCoccYMDXEIWYTs3CwIDAQAB -----END PUBLIC KEY----- 把公钥保存在文件里。

    注意这个是2048位的公钥应该是9行或者10行,不能为1行,不然PHP的openssl_pkey_get_public无法读取,pub_key_id的结果为false,如果没有-----BEGIN PUBLIC KEY-----和-----END PUBLIC KEY-----可以自己加上,最后保存到一个rsa_public_key.pem文件中。

    好了,现在已经有了所有的东西,先看签名函数
     1 <?php 2 /** 3  * 签名字符串 4  * @param $prestr 需要签名的字符串 5  * return 签名结果 6  */ 7 function rsaSign($prestr) { 8     $public_key= file_get_contents('rsa_private_key.pem'); 9     $pkeyid = openssl_get_privatekey($public_key);10     openssl_sign($prestr, $sign, $pkeyid);11     openssl_free_key($pkeyid);12     $sign = base64_encode($sign);13     return $sign;14 }15 ?>
    注意点:

    1.$prestr的内容和MD5一样(参见手册,但不包含最后的MD5密码)
    2.签名用商户私钥
    3.最后的签名,需要用base64编码
    4.这个函数返回的值,就是这次请求的RSA签名。

    验签函数:

     1 <?php 2 /** 3  * 验证签名 4  * @param $prestr 需要签名的字符串 5  * @param $sign 签名结果 6  * return 签名结果 7  */ 8 function rsaVerify($prestr, $sign) { 9     $sign = base64_decode($sign);10     $public_key= file_get_contents('rsa_public_key.pem');11     $pkeyid = openssl_get_publickey($public_key);12     if ($pkeyid) {13         $verify = openssl_verify($prestr, $sign, $pkeyid);14         openssl_free_key($pkeyid);15     }16     if($verify == 1){17         return true;18     }else{19         return false;20     }21 }22 ?>
    注意点:
    1.$prestr的内容和MD5一样(参见手册)
    2.$sign是支付宝接口返回的sign参数用base64_decode解码之后的二进制
    3.验签用支付宝公钥
    4.这个函数返回一个布尔值,直接告诉你,验签是否通过

    支付宝官方提供的PHP版SDKdemo中只对MD5加密方式进行了处理,但android端和ios端 请求支付宝加密方式只能用RSA加密算法,这时服务端PHP就无法验证签名了,所以需要对demo进行一些修改。

    1、修改alipay_notify.class.php文件
    verifyNotify 函数第46行
    $isSign = $this->getSignVeryfy($_POST, $_POST['sign']);
    改成
    $isSign = $this->getSignVeryfy($_POST, $_POST['sign'], $_POST['sign_type']);

    verifyReturn函数第83行
    $isSign = $this->getSignVeryfy($_GET, $_GET['sign']);
    改成
    $isSign = $this->getSignVeryfy($_GET, $_GET['sign'],$_GET['sign_type']);

    getSignVeryfy 函数 116行
    function getSignVeryfy($para_temp, $sign) {
    改成
    function getSignVeryfy($para_temp, $sign,$sign_type) {
    getSignVeryfy 函数 127行
    switch (strtoupper(trim($this->alipay_config['sign_type']))) {
    case 'MD5' : $isSgin = md5Verify($prestr, $sign, $this->alipay_config['key']); break; default : $isSgin = false; }
    改成
    switch (strtoupper(trim($sign_type))) {
    case 'MD5' : $isSgin = md5Verify($prestr, $sign, $this->alipay_config['key']); break;
    case 'RSA' : $isSgin = rsaVerify($prestr, $sign); break; default : $isSgin = false; } 2、新建一个alipay_rsa.function.php文件
     1 <?php 2 /* * 3  * RSA 4  * 详细:RSA加密 5  * 版本:3.3 6  * 日期:2014-02-20 7  * 说明: 8  * 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。 9  * 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。10  */11 /**12  * 签名字符串13  * @param $prestr 需要签名的字符串14  * return 签名结果15  */16 function rsaSign($prestr) {17     $public_key= file_get_contents('rsa_private_key.pem');18     $pkeyid = openssl_get_privatekey($public_key);19     openssl_sign($prestr, $sign, $pkeyid);20     openssl_free_key($pkeyid);21     $sign = base64_encode($sign);22     return $sign;23 }24 /**25  * 验证签名26  * @param $prestr 需要签名的字符串27  * @param $sign 签名结果28  * return 签名结果29  */30 function rsaVerify($prestr, $sign) {31     $sign = base64_decode($sign);32     $public_key= file_get_contents('rsa_public_key.pem');33     $pkeyid = openssl_get_publickey($public_key);34     if ($pkeyid) {35         $verify = openssl_verify($prestr, $sign, $pkeyid);36         openssl_free_key($pkeyid);37     }38     if($verify == 1){39         return true;40     }else{41         return false;42     }43 }44 ?>

    最后要说的是官方提供的手册上说的基本上都是正确的,只是有些地方没有说的很详细,开发的时候一定要多参考,大致就是这样,祝大家好运。

    PHP编程

    郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

  • 发表评论 共有条评论
    用户名: 密码:
    验证码: 匿名发表