需求
支付宝小程序端,获取到加密的用户手机号数据,需要经过服务端对数据进行解密,得到用户的手机号
问题
用户信息为敏感信息,需要用到敏感信息加密解密方法中的方式进行解密
服务端为PHP,由于官方没有对应的演示demo,经过摸索测试,还是出现了验签不通过,并且解密不成功的情况
解决过程
1.分析官方的java实例代码
String response = "小程序前端提交的";//1. 获取验签和解密所需要的参数MapString, String openapiResult = JSON.parseObject(response, new TypeReferenceMapString, String() { }, Feature.OrderedField);String signType = StringUtil.defaultIfBlank(openapiResult.get("signType"), "RSA2");String charset = StringUtil.defaultIfBlank(openapiResult.get("charset"), "UTF-8");String encryptType = StringUtil.defaultIfBlank(openapiResult.get("encryptType"), "AES");String sign = openapiResult.get("sign");String content = openapiResult.get("response");//如果密文的boolean isDataEncrypted = !content.startsWith("{");boolean signCheckPass = false;//2. 验签String signContent = content;String signVeriKey = "你的小程序对应的支付宝公钥(为扩展考虑建议用appId+signType做密钥存储隔离)";String encryptType = "你的小程序对应的加解密密钥(为扩展考虑建议用appId+encryptType做密钥存储隔离)"//如果是加密的报文则需要在密文的前后添加双引号if (isDataEncrypted) { signContent = """ + signContent + """;}try { signCheckPass = AlipaySignature.rsaCheck(signContent, sign, signVeriKey, charset, signType);} catch (AlipayApiException e) { //验签异常, 日志}if(!signCheckPass) { //验签不通过(异常或者报文被篡改),终止流程(不需要做解密) throw new Exception("验签失败");}//3. 解密String plainData = null;if (isDataEncrypted) { try { AlipayEncrypt.decryptContent(content, encryptType, decryptKey, charset); } catch (AlipayApiException e) { //解密异常, 记录日志 throw new Exception("解密异常"); }} else { plainData = content;}直接翻译这段代码为PHP的,并采用阿里云的SDK调用核心的两个方法。
经过不断的尝试,还是以失败告终。
2.分析定位阿里云SDK源码
阿里云的SDK中,首先通用的初始化了AopClient,将小程序的参数在里面初始化,其他操作并没有。
经过检查,AopClient中解密和校验的代码如下
/** rsaCheckV1 & rsaCheckV2 * 验证签名 * 在使用本方法前,必须初始化AopClient且传入公钥参数。 * 公钥是否是读取字符串还是读取文件,是根据初始化传入的值判断的。 **/public function rsaCheckV1($params, $rsaPublicKeyFilePath,$signType='RSA') {$sign = $params['sign'];$params['sign_type'] = null;$params['sign'] = null;return $this-verify($this-getSignContent($params), $sign, $rsaPublicKeyFilePath,$signType);}public function rsaCheckV2($params, $rsaPublicKeyFilePath, $signType='RSA') {$sign = $params['sign'];$params['sign'] = null;return $this-verify($this-getSignContent($params), $sign, $rsaPublicKeyFilePath, $signType);}function verify($data, $sign, $rsaPublicKeyFilePath, $signType = 'RSA') {if($this-checkEmpty($this-alipayPublicKey)){$pubKey= $this-alipayrsaPublicKey;$res = "-----BEGIN PUBLIC KEY-----" .wordwrap($pubKey, 64, "", true) ."-----END PUBLIC KEY-----";}else {//读取公钥文件$pubKey = file_get_contents($rsaPublicKeyFilePath);//转换为openssl格式密钥$res = openssl_get_publickey($pubKey);}($res) or die('支付宝RSA公钥错误。请检查公钥文件格式是否正确'); //调用openssl内置方法验签,返回bool值$result = FALSE;if ("RSA2" == $signType) {$result = (openssl_verify($data, base64_decode($sign), $res, OPENSSL_ALGO_SHA256)===1);;} else {$result = (openssl_verify($data, base64_decode($sign), $res)===1);}if(!$this-checkEmpty($this-alipayPublicKey)) {//释放资源openssl_free_key($res);}return $result;}/** * 在使用本方法前,必须初始化AopClient且传入公私钥参数。 * 公钥是否是读取字符串还是读取文件,是根据初始化传入的值判断的。 **/public function rsaDecrypt($data, $rsaPrivateKeyPem = null, $charset = null) {if($this-checkEmpty($this-rsaPrivateKeyFilePath)){//读字符串$priKey=$this-rsaPrivateKey;$res = "-----BEGIN RSA PRIVATE KEY-----" .wordwrap($priKey, 64, "", true) ."-----END RSA PRIVATE KEY-----";}else {$priKey = file_get_contents($this-rsaPrivateKeyFilePath);$res = openssl_get_privatekey($priKey);}($res) or die('您使用的私钥格式错误,请检查RSA私钥配置'); //转换为openssl格式密钥$decodes = explode(',', $data);$strnull = "";$dcyCont = "";foreach ($decodes as $n = $decode) {if (!openssl_private_decrypt($decode, $dcyCont, $res)) {echo "br/" . openssl_error_string() . "br/";}$strnull .= $dcyCont;}return $strnull;}function verify($data, $sign, $rsaPublicKeyFilePath, $signType = 'RSA') {if($this-checkEmpty($this-alipayPublicKey)){$pubKey= $this-alipayrsaPublicKey;$res = "-----BEGIN PUBLIC KEY-----" .wordwrap($pubKey, 64, "", true) ."-----END PUBLIC KEY-----";}else {//读取公钥文件$pubKey = file_get_contents($rsaPublicKeyFilePath);//转换为openssl格式密钥$res = openssl_get_publickey($pubKey);}($res) or die('支付宝RSA公钥错误。请检查公钥文件格式是否正确'); //调用openssl内置方法验签,返回bool值$result = FALSE;if ("RSA2" == $signType) {$result = (openssl_verify($data, base64_decode($sign), $res, OPENSSL_ALGO_SHA256)===1);;} else {$result = (openssl_verify($data, base64_decode($sign), $res)
版权声明
即速应用倡导尊重与保护知识产权。如发现本站文章存在版权问题,烦请提供版权疑问、身份证明、版权证明、联系方式等发邮件至197452366@qq.com ,我们将及时处理。本站文章仅作分享交流用途,作者观点不等同于即速应用观点。用户与作者的任何交易与本站无关,请知悉。













