php api接口的签名机制能够有效的数据的安全性以及解决重复提交的问题,下面我们来一一说明。
1、首先说一句什么是接口:接口简单来说就是服务器端用来返回给其他程序或者客户端数据的桥梁
2、接口的作用:根据固定参数返回固定数据,比如客户端传a=1,那么服务器端返回a的姓名,客户端传a=2,服务器端返回a的性别,而不会返回其他数据。
3、signature签名的作用:保证接口与数据的安全
4、token的作用:和PC登陆的session一样,作为用户进入的唯一票据
例如:app与服务器端的接口、java与php之间不同程序的接口,这些接口一般通过json格式传输数据
所以为了保证移动端和服务端数据传输相对安全,需要对接口进行加密传输。
接口签名验证固定参数: 接口签名验证固定参数是客户端调用所有接口时都需要传递的参数。用于接口版本管理(旧版本的安卓app依然可以使用)、安全校验等目的。 os String 客户端操作系统名称 例如"android", "ios" uuid String 移动设备唯一标识符 例如安卓手机的IMEI,苹果手机的UUID version String 客户端版本号 例如"1.0","2.0"(接口设计高版本接口要兼容低版本的接口) timestamp long 客户端调用接口时的时间戳 signature String 客户端接口调用签名
timestamp参数在防止数据重复提交中有这举足轻重的作用,因为每一个请求的时间都是不一样的,我们可以精确处理到毫秒或者微妙级。
签名算法介绍(可以根据实际变更其他算法使用):
对除去signature外的所有参数,按参数名的字典顺序排序后计算sha1值。
例如,某个接口的参数"mobile=18600933630&verifyCode=135466&os=android&uuid=GB1303EA&version=1.0×tamp=1442067125464"
a) 按参数名的字典顺序排序成 "mobile=18600933630os=androidtimestamp=1442067125464uuid=GB1303EAverifyCode=135466version=1.0"
b) signature值为字符串"mobile=18600933630os=androidtimestamp=1442067125464uuid=GB1303EAverifyCode=135466version=1.0"的sha1值
注意:简而言之,签名设计的原则就是保证服务器所接收到的数据是自己的APP端传过来的,而不是其他人非法调用的。
对于生成后的sha1值我们也要进行加密处理。这里面有两种情况
a) 在APP端给签名加密时需要加上特有固定参数,服务器也是加上特有固定参数,从而来保证一对一的传输,每个接口都需要调用该签名验证方法.下面的php代码用此种方法处理。
b) 可以用RSA对sha1值进行加密处理,服务器配置好RSA环境。
openssl genrsa -out rsa_private_key.pem 1024
openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt -out private_key.pem
openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
第一条命令生成原始 RSA私钥文件 rsa_private_key.pem,第二条命令将原始 RSA私钥转换为 pkcs8格式,第三条生成RSA公钥 rsa_public_key.pem
从上面看出通过私钥能生成对应的公钥,因此我们将私钥private_key.pem用在服务器端,公钥发放给android跟ios等前端
第二步,php服务器端,使用openssl方法来进行加密解密类,代码如下:
<?php
/**
* @author alun (http://alunblog.duapp.com)
* @version 1.0
* @created 2013-5-17
*/
class Rsa
{
private static $PRIVATE_KEY = \'-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAM9nUm7rPNhSgvsd
jMuCd5E7IMJB/80A1YY7jYV9fBCKdhVKmqea26QYuw6FW7B00fppEUTSazduSmn9
Yvhx9UOCcI75b0nq9FWm5O4P+Kp8l31M1pwsJ3cm+DceGOrFsl47vh9idiqj+abI
lJ4sTmJmDghmbks9YFlZSndQsIBlAgMBAAECgYAasa6vbgF3yi7niScc7l7bR2Pw
/LOivA+/ZhzR6JO2QUvvc5myJsFMPo6c0Nc7P93iv/EkDX0VNlHHkIBTf79URHXM
gXwMad4pHAeOiqxk5A9w/szDCBoETngtoqQGJq+QINxwPVvDEO4i224Uj3MKg2fo
4SDy3P1GCAAj1ahNoQJBAP4FV9vLWdLOOwOLnBpXt6vru4HT5VIf9fCeBIemuQ4C
/yRtgU38zXWgZ8AAmS6EjBEUDnN/tWid6UBKfgPDwAkCQQDRBP+Y9wIYIaSxeL7B
nHhPT25yAJCGK+l6r2qeaHVQr81O9YjusEi8E2M5OxCRolKxC3L7hrLJX8z1oyOV
dNx9AkBqYGhzpgv+qNiz2mJL8dH8ECMc8lTFeJbw5eu1tw8mHAEnCyisNSMBkGQC
Vv3PKjjR6hlHKwMYRZDpmIh/IRmpAkEAr1soLGaeZSxkhVetgbUJ4k/bct0yYr4Y
ZQshwcAVHBpBforT1JwkiVUim3MIFYY/JbVbQ9XfzL4Ir9OsGMkv6QJAPaQnyNY5
/D0PhXqODOM6jtAHHRfaSi4gve6AZ0iRz6YlB8beJ1ywZaJZWD9Cuw3zy4dDpCOn
A4tBsIdpMMoT+w==
-----END PRIVATE KEY-----\';
/**
*返回对应的私钥
*/
private static function getPrivateKey(){
$privKey = self::$PRIVATE_KEY;
return openssl_pkey_get_private($privKey);
}
/**
* 私钥加密
*/
public static function privEncrypt($data)
{
if(!is_string($data)){
return null;
}
return openssl_private_encrypt($data,$encrypted,self::getPrivateKey())? base64_encode($encrypted) : null;
}
/**
* 私钥解密
*/
public static function privDecrypt($encrypted)
{
if(!is_string($encrypted)){
return null;
}
return (openssl_private_decrypt(base64_decode($encrypted), $decrypted, self::getPrivateKey()))? $decrypted : null;
}
}
?>
app在访问接口是用对应的RSA公钥进行加密,传到服务器端后用私钥进行解密
固定参数的验证php方法:
public static function checkSign($args,$signature,$signtype = \'yes\')
{
if($signtype == \'no\') //上线时去除该部分,必须验证签名
{
return true;
}
if(!$args || !$signature)
{
return false;
}
if (time() - $args[\'timestamp\'] > 300) //同一签名调用时间限制
{
return false;
}
$args[\'xiaoming\'] = \'wuyingqi431\'; //特有固定参数
ksort($args); //按数组的键排序
$sign = \'\';
foreach($args as $k => $v)
{
$sign .= $k . \'=\' . $v;
}
$sign = sha1($sign); //加密
if($sign == $signature)
{
return true;
}
return false;
}
签名验证方法调用(其他必须传的固定参数也需要加入到$args数组当中):
$args = $res = array();
//下面是每个接口的参数(分为固定参数和不固定参数,固定参数必传)
$args[\'mobile\'] = r_get(\'mobile\');
//下面是签名固定参数
$args[\'os\'] = $_POST[\'os\'];
$args[\'uuid\'] = $_POST[\'uuid\'];
$args[\'version\'] = $_POST[\'version\'];
$args[\'timestamp\'] = $_POST[\'timestamp\'];
$signature = $_POST[\'signature\'];
$signtype = $_POST[\'signtype\'];
$check = appuser::checkSign($args,$signature,$signtype);
if(!$check)
{
$res[\'msg_code\'] = 99999; //签名错误
v_json($res);
}
处理签名的机制也可以对接口要传递的参数用RSA进行加密处理,此处代码没有对传递的参数做加密处理。
类似关于签名的文章:http://www.cnblogs.com/codelir/p/5327462.html