zoukankan      html  css  js  c++  java
  • API接口安全加强设计方法

    前面两篇相关文章:

    Web Api 内部数据思考 和 利用http缓存优化 Api

    Web Api 端点设计 与 Oauth

    1.开放的接口

    这样的接口我们天天都在接触,例如查快递,你查天气预报,你查飞机,火车班次等,这些都是有公共的接口。

    例如腾讯的开放平台:

    <?php
    
    /**
     * OpenAPI V3 SDK 示例代码,适用于大部分OpenAPI。如果是上传文件类OpenAPI,请参考本SDK包中的“Test_UploadFile.php”文件中的示例代码。
     *
     * @version 3.0.4
     * @author open.qq.com
     * @copyright © 2012, Tencent Corporation. All rights reserved.
     * @History:
     *               3.0.4 | coolinchen | 2012-09-07 10:20:12 | initialization
     */
    
    
    require_once 'OpenApiV3.php';
    
    // 应用基本信息
    $appid = 100657839;
    $appkey = 'b96b85196a04ff2ef08707f43979db15';
    
    // OpenAPI的服务器IP 
    // 最新的API服务器地址请参考wiki文档: http://wiki.open.qq.com/wiki/API3.0%E6%96%87%E6%A1%A3 
    $server_name = '119.147.19.43';
    
    
    // 用户的OpenID/OpenKey
    $openid = 'E098C1E975A2459E534B48FB3224CFB6';
    $openkey = '05219DB6D7C04CA0B3F01A51D32635E3';
    
    // 所要访问的平台, pf的其他取值参考wiki文档: http://wiki.open.qq.com/wiki/API3.0%E6%96%87%E6%A1%A3 
    $pf = 'qzone';
    
    
    $sdk = new OpenApiV3($appid, $appkey);
    $sdk->setServerName($server_name);
    
    $ret = get_user_info($sdk, $openid, $openkey, $pf);
    print_r("===========================
    ");
    print_r($ret);
    
    /**
     * 获取好友资料
     *
     * @param object $sdk OpenApiV3 Object
     * @param string $openid openid
     * @param string $openkey openkey
     * @param string $pf 平台
     * @return array 好友资料数组
     */
    function get_user_info($sdk, $openid, $openkey, $pf)
    {
        $params = array(
            'openid' => $openid,
            'openkey' => $openkey,
            'pf' => $pf,
        );
        
        $script_name = '/v3/user/get_info';
        return $sdk->api($script_name, $params,'post');
    }

    2.接口参数加密(基础加密)

    验证彼此约定好的key,验证通过,即可调用api。

      /**
          * 签名验证
          * 
          * @version 2017-08-14 
          */    
         function checkSign( $dataAry )
         {
            if(GAME_KEY == $dataAry['sign']) {   //GAME_KEY为 项目中的key , sign 为传递过来的签名,简单的验证是否对等,便通过
                return true;
            }
            
            return false;
         }
    
       //验证签名 不通过直接返回
         if(!checkSign($paramsAry)) {
            $retCode = 105;
            echo makeReturn($paramsAry,$retCode);
            exit();
         }

    这样子做的缺点如下:

    1 如果不小心把key泄露,那么很容易被他人调用接口

    2 开发者经常把sign附带于URL中进行请求,这样子容易被获取到URL请求参数,进而拿到sign

    加强方法:

    1 把URL请求参数进行base64为加密后再请求,或其他加密方式,将请求参数进行加密后,再请求

    2 限制可请求接口的ip 【一般用于充值等高防范的接口中】

    3.变换的接口参数加密【较为安全】

    key 不会永远都是安全的,也有可能被泄露,那么我们可以怎么做呢?我们可以生成变换的签名sign,且辅助其他参数进行排序变化加密

    例如对所有的参数(加上时间戳),按照首字母进行排序后,进行md5或sha加密,这时候每次生成的sign都是变化的,其他人即使拿到了key,如果不知道排序方式与加密方式,那么是无法算出sign的。

    例如:

    /**
         * 生成签名
         * 
         * @param $params 参数列表 数组 array('param1'=>'value1','param2'=>'value3',...)
         * @param $key 密钥 默认从配置文件取(GAME_KEY)
         */
        function genSign($params,$key='')
        {
            if($key == '') {
                $key = GAME_KEY;
            }    
            //过滤空值
            $paraFilter = array();
            while (list ($k, $v) = each ($params)) {
                if($k == 'sign' || $v == '')continue;
                else    $paraFilter[$k] = $params[$k];
            }
            
            //升序排列数
            ksort($paraFilter);
            reset($paraFilter);
            
            //生成参数字符串
            $paramsString  = "";
            while (list ($k, $v) = each ($paraFilter)) {
                $paramsString.=$k."=".$v."&";
            }
            //去掉最后一个&字符
            $paramsString = substr($paramsString,0,count($paramsString)-2);        
            //如果存在转义字符,那么去掉转义
            if(get_magic_quotes_gpc()){$paramsString = stripslashes($paramsString);}
            
            //加上key,进行md5
            $paramsString .='&key='.$key;
            $sign = md5($paramsString);
            
            return $sign;
        }

    可加强点:

    1 尾部带上双方约定好的key,再进行md5与sha同时加密

    2 url参数同时也要进行base64或者其他加密,例如最后能看到的请求url为:

    http://www.example.com/pay.php?data = SDDLKFKDKFLDHOIDHSALFSALDJALDSSALKJLDJSALDMSA

    3 不要明显的提示缺少什么参数,而且准确的使用错误码。

    4 . 变换的接口参数加密 + ip验证【非必须】 + 时效性检查 + https 【安全性高】

    只有特定的ip,才允许请求这个接口:

    /**
     * 获取客户端IP地址
     *
     */
    function getIp()
    {
        $realip='';
        if (isset($_SERVER)){
            if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])){
                $realip = $_SERVER["HTTP_X_FORWARDED_FOR"];
            } else if (isset($_SERVER["HTTP_CLIENT_IP"])) {
                $realip = $_SERVER["HTTP_CLIENT_IP"];
            } else {
                $realip = $_SERVER["REMOTE_ADDR"];
            }
        } else {
            if (getenv("HTTP_X_FORWARDED_FOR")){
                $realip = getenv("HTTP_X_FORWARDED_FOR");
            } else if (getenv("HTTP_CLIENT_IP")) {
                $realip = getenv("HTTP_CLIENT_IP");
            } else {
                $realip = getenv("REMOTE_ADDR");
            }
        }
         
        return $realip;
    }
    
    if(getIp() != '特定的ip'){
      echo makeReturn($paramsAry,$retCode);
        exit();
    }

    进行时效性检查:

        /**
         * 检查是否url过期
         * @param int $ts 时间戳
         * @param int $limitTime 有效期:默认为5分钟
         * @return string or boolean 成功且对方有返回值则返回
         */
        function checkTime($ts, $limitTime='300')  // 5分钟的有效期
        {
            $sencond = abs(time()-$ts);
            if ($sencond<=$limitTime)
            {
                return true;
            }
            return false;
        }

    HTTPS这块相对比较麻烦,我们项目所用的是免费版本的,所以经常弹出验证框。后面终于买了个收费版本,用起来挺好。

    4 . 总结

    在安全的同时,要根据业务进行接口的调整,例如:

    1 API版本的迭代规范,版本分支(例手游项目接口迭代比较重要),开发规范,模块管理(例如页游对接平台较多,模块管理比较重要)。

    2 客户端与服务端的双向验证,很多时候大部分都是服务端验证,然后返回错误码,客户端进行错误码验证是否正确,某些情况下,我们也可以服务端验证通过后,客户端同时也进行验证服务端返回的内容。

    3 可以在限定ip下,请求唯一入口api来获取其他接口的key,这也是一个不错的办法。key可以随便改变且不用通知接入方。

  • 相关阅读:
    75. InputStreamReader和OutputStreamWriter(转换流--字节流转换成字符流)
    74. 编码与解码
    73. PrintStream(打印流)
    72.Properties(配置文件)
    71 Serializable(序列化和反序列化)
    70. SequenceInputStream(文件合并)
    Rabin-Karp指纹字符串查找算法
    优先队列
    版本管理工具svn简介
    php 2038年问题
  • 原文地址:https://www.cnblogs.com/zhenghongxin/p/7279553.html
Copyright © 2011-2022 走看看