zoukankan      html  css  js  c++  java
  • PHP 开发API接口签名验证

    就安全来说,所有客户端和服务器端的通信内容应该都要通过加密通道(HTTPS)传输,明文的HTTP通道将会是man-in-the- middle及其各种变种攻击的温床。所谓man-in-the-middle攻击简单讲就是指恶意的黑客可以在客户端和服务器端的明文通信通道上做手 脚,黑客可以监听通信内容,偷取机密信息,甚至可以篡改通信内容,而通过加密后的通信内容理论上是无法被破译的。

    URL签名生成规则

    API的有效访问URL包括以下三个部分:
    1. 资源访问路径,如/v1/deal/find_deals;
    2. 请求参数:即API对应所需的参数名和参数值param=value,多个请求参数间用&连接如deal_id=1-85462&appid=00000;
    3. 签名串,由签名算法生成

    签名算法如下:

    1. 对所有请求参数进行字典升序排列;
    2. 将以上排序后的参数表进行字符串连接,如key1value1key2value2key3value3...keyNvalueN;
    3. app secret作为后缀,对该字符串进行SHA-1计算,并转换成16进制编码;
    4. 转换为全大写形式后即获得签名串

     

    注意:请保证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":"u5ba2u6237u670du52a1u5217u8868","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

  • 相关阅读:
    INFO: InstallShield不同版本对中文字符串的支持程度
    Basic INFO: InstallShield 2012安装过程
    [Android] 打印Log的行号、函数、类名
    gridgian 网格计算
    Activity及Dialog的全透明
    设计工具
    ps 多图层扣图
    spket js ide
    a 的样式
    js开发规范
  • 原文地址:https://www.cnblogs.com/dcb3688/p/4608008.html
Copyright © 2011-2022 走看看