zoukankan      html  css  js  c++  java
  • API安全设计(1)

    1、API简介

    这段时间和外部公司合作,一直在写对外API接口。提供的API接口是基于http协议的,也是无状态的。每次请求都必须带上身份认证信息。后台服务对身份信息进行校验。
    基于HTTP协议的API身份认证有很多种方式,有HTTP Basic,HTTP Digest,API KEY,Oauth,JWK等方式,我这里只讲基于项目中的API KEY校验。

    2、API KEY

    API接口均通过请求头(HEADER)中传递的 TOKEN(授权令牌)来进行身份认证和鉴权, 系统会在校验 TOKEN 的正确性和时效性。
    API Key就是经过用户身份认证之后服务端给客户端分配一个API Key,类似:http://test/api/package/create,
    将生成的token放在头部进行传输。

    一般的处理流程如下: 一个简单的设计示例如下:

    3、客户端生成TOKEN

    计算sign和token的PHP参考代码:
    设计思路:
    user_id: 授权客户的 id;
    app_key:开通 API 授权后获得的私钥;
    ts: 发起请求时的时间戳, 精确到秒,这个值跟接收到请求时的服务器时间戳,值偏差(正或负)超过 1200 秒( 20 分钟)时,请求会被拒绝,要求调用方重新生成;
    token(请使用 CCT +08:00 中国北京时间);
    sign: 签名字符串,对输入参数的键值key进行升序排列,转换成型如k1=v1&k2=v2的字符串,然后拼接时间戳和app_key,最后进行sha1混淆;

    function getToken($inputArr)
    {
        //当前unix时间戳
        $userId = '3322991';
        $appKey = 'abc123';
        $ts = time();
        $sign = get_sign($inputArr, $ts, $appKey);
        $token = base64_encode($userId . ',' . $ts . ',' . $sign);
    
        return $token;
    }
    
    function getSign($inputArr, $ts, $appKey)
    {
        ksort($inputArr);
        $inputStr = urlencode(http_build_query($inputArr));
        $sign = sha1($inputStr . $ts . $appKey);
        return $sign;
    }
    
    
    

    4、服务端解析TOKEN

    后台服务端解析TOKEN的主要思路是:
    1、从头部header获取token参数;
    2、根据token得到user_id、ts和sign;
    3、然后根据user_id、ts和请求参数新生成签名sign;
    4、校验app_key是否合法,校验ts的时效性,校验新生成的签名sign和传的签名sign是否一致。

        /**
         * 解析TOKEN
         * @param $token
         * @param array $inputArr
         * @return array
         */
        function decToken($token, $inputArr = [])
        {
            $tokenInfo = base64_decode($token);
            $tokenInfo = explode(',', $tokenInfo);
            if (count($tokenInfo) != 3) {
                Error::trigger('TOKEN信息错误');
            }
            
            list($userId, $time, $sign) = $tokenInfo;
            Log::info("check token params,userId:{$userId},time :{$time},sign:{$sign},inputArr:" . json_encode($inputArr));
            
            // 时间有效性校验
            if (abs(time() - $time) > App::getConfig('api_token_expire_time')) {
                Error::trigger(Error::ERR_PARAM_TOKEN_TIME);
            }
            
            // 签名校验
            $tokenObj = new Token();
    		// 获取用户appKey信息,根据实际项目生成app_key的规则而定
            $appKey = '*****************';
            
            $generateSign = $this->getSign($inputArr, $time, $appKey);
            
            // 校验参数生成的token
            $newToken = $this->getToken($inputArr, $userId, $appKey, $time);
            Log::info("token:{$token},newToken:" . json_encode($newToken));
            Log::info("sign:{$sign},newSign:" . json_encode($generateSign));
            
            if ($sign !== $generateSign) {
                Error::trigger(Error::ERR_PARAM_TOKEN_SIGN);
            }
            
            Log::info('token decoded successfully');
            return $appKey;
        }
    
  • 相关阅读:
    前端几个常用简单的开发手册拿走不谢
    初中级前端开发工程师如何提升个人能力?
    初中级前端开发工程师如何提升个人能力?
    【程序人生】那些工作之外的技术挣钱方式
    Java EE (13) -- 常用的基础结构模式
    3、数据类型
    洛谷——P2299 Mzc和体委的争夺战
    codevs——T1214 线段覆盖
    洛谷——P1106 删数问题
    洛谷——P1031 均分纸牌
  • 原文地址:https://www.cnblogs.com/jaspersong/p/8474617.html
Copyright © 2011-2022 走看看