就安全来说,所有客户端和服务器端的通信内容应该都要通过加密通道(HTTPS)传输,明文的HTTP通道将会是man-in-the- middle及其各种变种攻击的温床。所谓man-in-the-middle攻击简单讲就是指恶意的黑客可以在客户端和服务器端的明文通信通道上做手 脚,黑客可以监听通信内容,偷取机密信息,甚至可以篡改通信内容,而通过加密后的通信内容理论上是无法被破译的。
URL签名生成规则
API的有效访问URL包括以下三个部分: |
签名算法如下:
1. 对所有请求参数进行字典升序排列; |
注意:请保证HTTP请求数据编码务必为UTF-8格式,URL也务必为UTF-8编码格式。
举个实例:
PHP服务端先要给开发者(APP)分配一个appid与appsecret (正常情况下,开发者要到服务提供商的官网申请),作为客户端,需要保留好官方颁发的appid & appsecret
appid会在请求中作为一个应用标识参与接口请求的参数传递,appsecret 将作为唯一不需要参数传递,但是它将作为验证当前请求的关键参数,只有应用开发者和颁发的服务端才知道。由于签名是依靠同样的算法加密实现,因此,应用端和服务端可以计算出相同的签名值,签名实际意义在于服务端对客户端的访问身份认证。在某种意义上签名机制有点类似用公钥方法签名,用每个应用对应的私钥值来解密,只是这种解密过程实质就是核对签名参数值的过程。
假设分配:
$appid=5288971; $appsecret= 'r5e2t85tyu142u665698fzu';
移动客户端,需要请求服务列表(以下代码可以为java或sf等移动端编写)
请求地址: http://web.com/server/list
参数:
$array=[ 'appid'=>5288971, 'menu'=>'客户服务列表', 'lat'=>21.223, 'lng'=>131.334 ];
对应签名算法
// 1. 对加密数组进行字典排序 防止因为参数顺序不一致而导致下面拼接加密不同 ksort($array); // 2. 将Key和Value拼接 $str = ""; foreach ($array as $k => $v) { $str.= $k.$v; } //3. 通过sha1加密并转化为大写 //4. 大写获得签名 $restr=$str.$appsecret; $sign = strtoupper(sha1($restr));
将生产的sign签名一起写入array中,通过约定好的method方式发送参数到请求接口
$array['sign']=$sign;
打印$array
Array ( [appid] => 5288971 [menu] => 客户服务列表 [lat] => 21.223 [lng] => 131.334 [sign] => C096D7811E944386CE880597BA334A5AB640B088 )
客户端将数据封装xml或Json发送到服务端,服务端先解析
{"appid":5288971,"menu":"\u5ba2\u6237\u670d\u52a1\u5217\u8868","lat":21.223,"lng":131.334,"sign":"C096D7811E944386CE880597BA334A5AB640B088"}
$serverArray= json_decode($json,TRUE);
服务端查询appid对应的密钥
$model=Model::find()->where("appid=:appid")->params([":appid"=>$serverArray['appid']])->one(); if($model){ $serverSecret=$model->appsecret; }
按照相同的字典排序与算法生成服务端的$sign ,判断$sign 是否相同。
$clientSign=$serverArray['sign']; unset($serverArray['sign']); #生成服务端str $serverstr = ""; foreach ($serverArray as $k => $v) { $serverstr.= $k.$v; } $reserverstr=$serverstr.$serverSecret; $reserverSign = strtoupper(sha1($reserverstr)); if($clientSign!=$reserverSign){ die('非法请求'); }else{ // your code continue; }
在仅适用短信登录做手机端app时,可以设置secret的过期时间,短信登录后,保存appid(userid)与密钥secret,每当用户打开APP时,先联网请求登录是否过期,过期重新短信登录获取新的secret。
附加:
有时,我们使用hash_hmac进行加密(我们项目中使用……)
/* * 生成签名,$args为请求参数,$key为私钥 */ function makeSignature($args, $key) { if(isset($args['sign'])) { $oldSign = $args['sign']; unset($args['sign']); } else { $oldSign = ''; } ksort($args); $requestString = ''; foreach($args as $k => $v) { $requestString .= $k . '=' . urlencode($v); } $newSign = hash_hmac("md5",strtolower($requestString) , $key); return $newSign; }
javascript 进行加密签名
微信小程序开发的时候,为了数据的安全,也可以用js对数据签名,发送服务器进行效验认证.
先引入md5.js
<script src="https://cdn.bootcss.com/blueimp-md5/2.10.0/js/md5.js"></script>
var postData =<?php echo json_encode($data); ?>; var token ='<?php echo token; ?>'; /** * json 排序 * 先排序再toLower,所以Did 在appid 之前 */ function jsonSort(jsonObj) { let arr = []; for (var key in jsonObj) { arr.push(key) } arr.sort(); let str = ''; for (var i in arr) { str += arr[i].toLowerCase() + "=" + jsonObj[arr[i]].toLowerCase(); } return str } strData = jsonSort(postData); var sign = md5(strData, token); postData['sign'] = sign; console.log(postData);
JS-PHP 加密解密demo: https://files.cnblogs.com/files/dcb3688/php.javascript.encrypMD5.php.7z