Skip to content

Instantly share code, notes, and snippets.

@crossai-2033
Created September 24, 2015 04:01
Show Gist options
  • Save crossai-2033/55797ef1e808948bd825 to your computer and use it in GitHub Desktop.
Save crossai-2033/55797ef1e808948bd825 to your computer and use it in GitHub Desktop.
Api接口设计算法
当我们设计对外Api接口的时候,要考虑接口的安全性,防止被拦截或者被重放攻击等,所以接口的对外设计要有一套验证机制。
接口的设计主要双方就是接口提供方以及接口使用方,所考虑的方案就是双向加密认证,双方使用一个统一的Token,然后用Token加上固定的混淆规则
然后双方都使用同样的规则来产生一个认证sign来验证。
<!-- Api验证函数 -->
<?php
class ApiCheck
{
const MAX_TIME_DIFF = 600;
const SIGN_CUT_BGN = 3;
const SIGN_CUT_CNT = 7;
public static function validParamTime($time)
{
$diff = abs($time - time());
return $diff < self::MAX_TIME_DIFF ? true : false;
}
public static function validParamSign($sign, $token, $params)
{
if (isset($params['sign'])) {
unset($params['sign']);
}
ksort($params);
$params_str = http_build_query($params);
$secret = md5(md5($params_str).$token);
$valid_sign = substr($secret, self::SIGN_CUT_BGN, self::SIGN_CUT_CNT);
return $sign == $valid_sign ? true : false;
}
}
// 调用接口时候先执行验证函数
private function verifyCommonParams()
{
if (false === ApiCheck::validParamTime($this->_request_params['t'])) {
throw new Exception(ErrnoKnowledge::E_DW2014_INVALID_PHONE, '时间参数不合法');
}
$appKey = $this->_request_params['appKey'];
$appInfo = $this->getAppInfo($appKey);
$appSecret = $appInfo['AppSecret'];
$token = $this->getApiToken($appKey, $appSecret); // 313c9a8d5c0c03425e30bf9b713fc059
if (false === ApiCheck::validParamSign($this->_request_params['sign'], $token, $this->_request_params)) {
throw new Exception(HErrnoKnowledge::E_DW2014_INVALID_PHONE, 'sign认证不正确');
}
}
public function getApiToken($appKey, $appSecret)
{
return md5('_app_'.$appKey.'_secret_'.$appSecret);
}
// 然后接口使用方的使用方法为
// 保证唯一key,并按照统一规则生成Token
function getToken()
{
$appKey = 'BaoMiTu';
$appSecret = 'df16e791bf8da7284a5b6ed56197fa28';
return md5('_app_'.$appKey.'_secret_'.$appSecret);
}
// API测试
$REQUEST_TIMEOUT = 3;
$REQUEST_RETRY = 3;
$curl = CurlSvc::ins();
$host = array('127.0.0.1');
$host = array();
// ------------------------>
// 按照统一规则生成API函数
$params = array( //请求参数
'appKey' => 'BaoMiTu',
't' => time(), //客户端时间和服务端时间的差值在一个允许的范围内
'nonce' => substr(md5(microtime(true).rand(0, 999)), 0, 16), //随机串,防重放攻击
);
$token = getToken(); //分配给客户端的token
ksort($params); //请求参数key按照字典升序排序
$params_str = http_build_query($params); //拼成k1=v1&k2=v2 ...的形式
$secret = md5(md5($params_str).$token); //md5后把token拼接到后面再次md5
$sign = substr($secret, 3, 7); //从下标3开始取7个字符即为最终签名
$time = time();
$url = "http://xxxx/weixin/getAccessToken?fmt=json&$params_str&sign=$sign";
echo $url;
echo "\r\n";
$response = $curl->get($url, $REQUEST_TIMEOUT, $host, $REQUEST_RETRY);
$http_code = $curl->getHttpCode();
$response = json_decode($response);
echo $response->data;
至此双方就形成了同一套加密规则,都使用同一个Token来进行了接口验证
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment