PHP API权限设计总结-系统sign验证规则
网络安全越来越发达的今天, 系统安全是每一位开发者都需要考虑的问题, 比如用户注册, 如果提交的数据不做安全验证, 那么有些人或许会提交一堆的垃圾数据,久而久之你的数据库中的僵死数据会非常的多,影响正常数据的查询效率,同时你的系统也许就在某一天over了。所以安全一直都是我们工作考虑的重点。那么一般都会对提交的数据做安全的验证 比如通用的sign加密验证, sign 究竟是怎么个验证方法呢?
1. 首先是数据库api, 表结构的设计取决于自己的情况, 最基本的设计:
字段 | type | Is null | Auto_increment | comment |
id | Int(11) | not | 自增id | |
Api_name | Varchar(25) | Not null | 应用的名称 | |
key | Varchar(32) | Not null | 应用的key | |
secret | Varchar(32) | Not null | 应用的密钥 |
2. 上面还没有提到sign究竟是怎么的回事儿呢?
第二步就是生成自己的sign, 每次提交的数据都要加上sign提交给后台。
Sign的算法一般都是采用对提交的数据进行排序后+secret后MD5
$key = "c4ca4238a0b923820dcc509a6f75849b";
$secret = "28c8edde3d61a0411511d3b1866f0636";
如:
$data = array(
'username' => 'anziguoer@sina.com',
'sex' => '男',
'age' => '12',
'addr' => '北京市海淀区'
);
// 传递的参数中必须有 key, sign, timestamp
$postData = array(
"key" => $key,
"timestamp" => time()
);
// 一般情况提交到后台的数据在除了要提交的信息还要加上一些验证的数据 ($postData就是这样的数据)
// 将用户提交的数据和必须的参数一起排序(正序或者是倒序都可以, 子要保证验证的算法和加密的算法一致即可)
// 获取sign
function getSign($secret, $data)
{
// 对数组的值按key排序
ksort($data);
// 生成url的形式
$params = http_build_query($data);
// 生成sign
$sign = md5($params.$secret);
return $sign;
}
//将用户的数据和默认的数据合并
$psotData = array_merge($postData, $data);
// 发送的数据中吧sign带上
$psotData[‘sign’] = getSign($secret, $data);
// 数据组合好后可以吧数据发送到后台
3. 第三步就是在服务器端吧得到的数据进行验证处理.
对必须的参数进行验证:
1) . 通过key在api的数据库中查找是否存在secret的值,没有则验证失败
2) . 对传递过来的数据中验证sign参数是否存在, 不存在, 验证失败。
3) . 对时间’timestamp’参数进行验证,大于10分钟的数据验证失败。
4) 、对出去sign的所有参数进行验证, 生成的sign和传递过来的sign参数是否一致, 不一致验证失败。
5) . 如果上面的有验证通过后就可以执行下面的逻辑代码.
/**
* 验证sign是否合法
* @param [type] $secret [description]
* @param [type] $data [description]
* @return [type] [description]
*/
function verifySign($secret, $data)
{
// 验证参数中是否有签名
if (!isset($data['sign']) || !$data['sign']) {
echo '发送的数据签名不存在';
die();
}
if (!isset($data['timestamp']) || !$data['timestamp']) {
echo '发送的数据参数不合法';
die();
}
// 验证请求, 10分钟失效
if (time() - $data['timestamp'] > 600) {
echo '验证失效, 请重新发送请求';
die();
}
$sign = $data['sign'];
unset($data['sign']);
ksort($data);
$params = http_build_query($data);
// $secret是通过key在api的数据库中查询得到
$sign2 = md5($params.$secret);
if ($sign == $sign2) {
die('验证通过');
}else{
die('请求不合法');
}
}
最后送上腾讯的sign加密原理:http://www.qcloud.com/wiki/签名参数sign生成说明
receive.php
<?php // 获取post的数组 $key = "c4ca4238a0b923820dcc509a6f75849b"; // $secret 是存储在数据库中, 可以根据传递过来的key在数据中的查询到secretZ12QAZ12 $secret = "28c8edde3d61a0411511d3b1866f0636"; $data = $_POST; verifySign($secret, $data); /** * 验证sign是否合法 * @param [type] $secret [description] * @param [type] $data [description] * @return [type] [description] */ function verifySign($secret, $data) { // 验证参数中是否有签名 if (!isset($data['sign']) || !$data['sign']) { echo '发送的数据签名不存在'; die(); } if (!isset($data['timestamp']) || !$data['timestamp']) { echo '发送的数据参数不合法'; die(); } // 验证请求, 10分钟失效 if (time() - $data['timestamp'] > 600) { echo '验证失效, 请重新发送请求'; die(); } $sign = $data['sign']; unset($data['sign']); ksort($data); $params = http_build_query($data); $sign2 = md5($params.$secret); if ($sign == $sign2) { die('验证通过'); }else{ die('请求不合法'); } } ?>
request.php
<?php $key = "c4ca4238a0b923820dcc509a6f75849b"; $secret = "28c8edde3d61a0411511d3b1866f0636"; $data = array( 'username' => 'anziguoer@sina.com', 'sex' => '男', 'age' => '12', 'addr' => '北京市海淀区' ); // 传递的参数中必须有 key, sign, timestamp $postData = array( "key" => $key, "timestamp" => time() ); $psotData = array_merge($postData, $data); $sign = getSign($secret, $psotData); $postData['sign'] = $sign; // 获取sign function getSign($secret, $data) { // 对数组的值按key排序 ksort($data); // 生成url的形式 $params = http_build_query($data); // 生成sign $sign = md5($params.$secret); return $sign; } $postData = array_merge($postData, $data); request($postData); /** * 发送服务器的数据 * @param [type] $postData [description] * @return [type] [description] */ function request($postData) { $curl = curl_init('http://host/receive.php'); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_POST, TRUE); curl_setopt($curl, CURLOPT_POSTFIELDS, $postData); $info = curl_exec($curl); curl_close($curl); print_r($info); }