对称加密
之前写接口的时候用到了签名验证,生成规则如下
1.根据参数名称,按照字典顺序,升序排序
2.拼接参数以及参数值,按照排序以后的key,value直接连接的方式,key和value之间不需要加任何的字符
3.将拼接以后的字符串前后加上签名密钥
4.进行MD5加密,然后转大写
生成部分(通过js)
function generateSign( params, secret_code )
{
var names = [];
for ( var name in params ) {
names.push( name );
}
names.sort();
var str = secret_code;
for ( var i = 0; i < names.length; i ++ ) {
var name = names[i];
str += name + params[name];
}
str += secret_code;
alert(str);
return hex_md5( str ).toUpperCase();
}
验证部分(后台php)
function generateSign( $partner, $params, $secret_code )
{
ksort( $params );
$stringToBeSigned = $secret_code;
foreach ( $params as $k => $v )
{
$stringToBeSigned .= "$k$v";
}
unset( $k, $v );
$stringToBeSigned .= $secret_code;
return strtoupper( md5( $stringToBeSigned ) );
}
主要流程是商户生成一个签名然后请求我们的时候我们要通过他们的签名密钥生成一个签名然后再验证正确性,这个例子是典型的对称加密,优点是生成方便解析速度快。但是密钥双方保存,一但一方丢失会有很大的危险。
非对称加密
随着项目的扩展,我们需要有自己的支付平台,因为涉及到支付,所以对于安全性也有一定的要求,因此商户请求接口的时候用到了RSA2(一种非对称加密方式)加密方式,非对称加密我理解为公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。如果不懂的话可以参考阮一峰大神的讲解http://www.ruanyifeng.com/blog/2011/08/what_is_a_digital_signature.html
这就需要改下规则了
1.商户生成一对密钥(公钥和私钥),公钥给我们,私钥自己留下。
2.我们拿到公钥之后存到对应的商户的属性里面,主要是为了分清不同商户对应的密钥。
3.商户请求接口的时候要根据自己的私钥生成一个签名放到自己的xml或者json数据中(生成方式下面)。
4.我们拿到xml或者json数据之后我们会分析数据找到sign,在进行下一步之前先要验证签名的正确性,这时就要取出相应商户的公钥来验证了。
以上是大致流程,下面是代码部分
生成(php)
public function do_sign()
{
$params = $_POST;
unset( $params[ 'sign' ] );
$partner = M( "partner" )->getByUK( 'code', $params[ 'partner' ] );
$private_key = $partner->getPropsValue( 'private_key' );
if( !$private_key )
{
throw new Exception( "商户属性配置中缺少私钥" );
}
$stringToBeSigned = get_sign_content( $params );
$res = "-----BEGIN RSA PRIVATE KEY-----\n" .
wordwrap( $private_key, 64, "\n", true ) .
"\n-----END RSA PRIVATE KEY-----";
( $res ) or die('您使用的私钥格式错误,请检查RSA私钥配置');
openssl_sign( $stringToBeSigned, $sign, $res, OPENSSL_ALGO_SHA256 );
$sign = base64_encode( $sign );
}
验证(php)
private function _checkSign( $data, $sign, $public_key )
{
$res = "-----BEGIN PUBLIC KEY-----\n" .
wordwrap( $public_key, 64, "\n", true ) .
"\n-----END PUBLIC KEY-----";
( $res ) or die( 'RSA公钥错误' );
$result = (bool)openssl_verify( $data, base64_decode( $sign ), $res, OPENSSL_ALGO_SHA256 );
return $result;
}
上面详细列出了验证的规则,生成的时候商户用自己的私钥生成签名,然后我们用公钥验证签名的正确性。
总结
之前对于这里很模糊,因为好多东西没有搞懂,现在有时间拿来研究发现也没有多难,也许就是一个点没有懂,平常写代码也一样,再难得问题也有突破口。