API安全设计

Posted Jaspersong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了API安全设计相关的知识,希望对你有一定的参考价值。

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;
    }

以上是关于API安全设计的主要内容,如果未能解决你的问题,请参考以下文章

用产品思维设计API—— 安全,就只能用HTTPS?

20155234 2017-2018-1《信息安全系统设计基础》课程总结

onActivityResult 未在 Android API 23 的片段上调用

RESTful api接口安全优雅设计

移动API设计与安全存储

Java并发编程:多线程环境中安全使用集合API(含代码)