電商API接口有哪些安全問(wèn)題?
如何保證API接口安全
接口的安全性主要圍繞Token、Timestamp和Sign三個(gè)機(jī)制展開(kāi)設(shè)計(jì),保證接口的數(shù)據(jù)不會(huì)被篡改和重復(fù)調(diào)用,下面具體來(lái)看:
Token授權(quán)機(jī)制:用戶(hù)使用用戶(hù)名密碼登錄后服務(wù)器給客戶(hù)端返回一個(gè)Token(通常是UUID),并將Token-UserId以鍵值對(duì)的形式存放在緩存服務(wù)器中。服務(wù)端接收到請(qǐng)求后進(jìn)行Token驗(yàn)證,如果Token不存在,說(shuō)明請(qǐng)求無(wú)效。
時(shí)間戳超時(shí)機(jī)制:用戶(hù)每次請(qǐng)求都帶上當(dāng)前時(shí)間的時(shí)間戳timestamp,服務(wù)端接收到timestamp后跟當(dāng)前時(shí)間進(jìn)行比對(duì),如果時(shí)間差大于一定時(shí)間(比如5分鐘),則認(rèn)為該請(qǐng)求失效,這個(gè)時(shí)間要保證足夠完成本次請(qǐng)求的同時(shí)盡量短,可以減少緩存服務(wù)器的壓力(見(jiàn)簽名機(jī)制)。
簽名機(jī)制:將Token和時(shí)間戳加上其他請(qǐng)求參數(shù)就行MD5或SHA-1算法(可根據(jù)情況加點(diǎn)鹽)加密,加密后的數(shù)據(jù)為本次請(qǐng)求的簽名sign,并將該簽名存放到緩存服務(wù)器中,超時(shí)時(shí)間設(shè)定為跟時(shí)間戳的超時(shí)時(shí)間一致(這就是為什么要盡量短,二者時(shí)間一致可以保證無(wú)論在timestamp規(guī)定時(shí)間內(nèi)還是外本URL都只能訪(fǎng)問(wèn)一次)。服務(wù)端接收到請(qǐng)求后以同樣的算法得到簽名,并跟當(dāng)前的簽名進(jìn)行比對(duì),如果不一樣,說(shuō)明參數(shù)被更改過(guò),直接返回錯(cuò)誤標(biāo)識(shí)。同一個(gè)簽名只能使用一次,如果發(fā)現(xiàn)緩存服務(wù)器中已經(jīng)存在了本次簽名,則拒絕服務(wù)。
sign生成規(guī)則及步驟:
① 第一步:將所有需要發(fā)送至服務(wù)端的請(qǐng)求參數(shù)(空參數(shù)值的參數(shù)、文件、字節(jié)流、sign除外)按照參數(shù)名ASCII碼從小到大排序(字典序)
注意:
????? l 參數(shù)名ASCII碼從小到大排序(字典序);
????? l 如果參數(shù)的值為空不參與簽名;
????? l 文件、字節(jié)流不參與簽名;
????? l sign不參與簽名;
????? l 參數(shù)名、參數(shù)值區(qū)分大小寫(xiě);
②第二步:將排序后的參數(shù)按照URL鍵值對(duì)的格式(即key1=value1&key2=value2…)拼接成字符串strA;
③第三步:在strA后面拼接上apiKey得到striSignTemp字符串,將strSignTemp字符串轉(zhuǎn)換為小寫(xiě)字符串后進(jìn)行MD5運(yùn)算,MD5運(yùn)算后得到值作為sign的值傳入服務(wù)端;
/*
* @desc 簽名函數(shù)
* @param $paramArr 系統(tǒng)參數(shù)
* @param $apiKey 私鑰
* @return string 返回簽名
*/
private function createSign ($paramArr,$apiKey) {
ksort($paramArr);
$sign='';
foreach ($paramArr as $key => $val) {
if ($key != '' && $val != '') {
$sign .= $key."=".$val."&";
}
}
$sign=rtrim($sign,"&");
$sign.=$apiKey;
$sign=strtolower($sign);
$sign = md5($sign);
return $sign;
}
簽名校驗(yàn):
/*
* @desc 簽名校驗(yàn)
* @param $token string 服務(wù)端分配的標(biāo)識(shí)(不同客戶(hù)端需使用不同的標(biāo)識(shí))
?*?@param?$timestamp?string?時(shí)間戳,UTC時(shí)間,以北京時(shí)間東八區(qū)(+8)為準(zhǔn)
?*?@param?$sign?string?簽名
* @param $privatekey string 私鑰
* @param $data 業(yè)務(wù)參數(shù)json格式
* @return bool
*/
private function checkAuth($token,$timestamp,$sign,$privatekey,$data){
//參數(shù)判斷
if(empty($token)){
????????????show(10001,'token不能為空!');
}
if(empty($timestamp)){
????????????show(10002,'時(shí)間戳不能為空!');
}
if(empty($data)){
????????????show(10004,'業(yè)務(wù)參數(shù)不能為空!');
}
if(empty($sign)){
????????????show(10006,'簽名不能為空!');
}
if(empty($privatekey)){
????????????show(10007,'私鑰不能為空!');
}
//時(shí)間校驗(yàn)
????????$expire_second=config('expire_second');
$timestamp_t=$timestamp+$expire_second;
if($timestamp_t<time()){
?????????????show(10008,'請(qǐng)求已經(jīng)過(guò)期!');
}
//系統(tǒng)參數(shù)
$paramArr=array(
'token'=>$token,
????????????'timestamp'=>$timestamp,
'data'=>$data,
);
//按規(guī)則拼接為字符串
????????$str?=?$this->createSign($paramArr,$this->privatekey);?
if($str != $this->sign){
?????????????show(10009,'驗(yàn)簽錯(cuò)誤!');
}
return true;
}
拒絕重復(fù)調(diào)用:客戶(hù)端第一次訪(fǎng)問(wèn)時(shí),將簽名sign存放到緩存服務(wù)器中,超時(shí)時(shí)間設(shè)定為跟時(shí)間戳的超時(shí)時(shí)間一致,二者時(shí)間一致可以保證無(wú)論在timestamp限定時(shí)間內(nèi)還是外 URL都只能訪(fǎng)問(wèn)一次。如果有人使用同一個(gè)URL再次訪(fǎng)問(wèn),如果發(fā)現(xiàn)緩存服務(wù)器中已經(jīng)存在了本次簽名,則拒絕服務(wù)。如果在緩存中的簽名失效的情況下,有人使用同一個(gè)URL再次訪(fǎng)問(wèn),則會(huì)被時(shí)間戳超時(shí)機(jī)制攔截。這就是為什么要求時(shí)間戳的超時(shí)時(shí)間要設(shè)定為跟時(shí)間戳的超時(shí)時(shí)間一致。拒絕重復(fù)調(diào)用機(jī)制確保URL被別人截獲了也無(wú)法使用(如抓取數(shù)據(jù))。
/**
* @desc 限制請(qǐng)求接口次數(shù)
* @return bool
*/
private?function?ask_count(){
$client_ip = $this->sys_get_client_ip();
$ask_url = $this->sys_GetCurUrl();
//限制次數(shù)
????$limit_num?=?config('api_ask_limit');?
//有效時(shí)間內(nèi),單位:秒
????$limit_time?=?config('api_ask_time');?
$now_time = time();
$valid_time = $now_time - $limit_time;
????$ipwhere['ip_name']?=?$client_ip;
$ipwhere['ask_url'] = $ask_url;
????$ipwhere['creatime']?=?array('>=',date('Y-m-d?H:i:s',$valid_time));
????$check_result?=?Db::table('log_ip_ask')->where($ipwhere)->count();??
if($check_result !=='0'){
if($check_result >= $limit_num){
show(10010,'已經(jīng)超出了限制次數(shù)!');
}
????}
????
????//執(zhí)行插入
$add_data = array(
'ip_name'=>$client_ip,
'ask_url'=>$ask_url,
'creatime'=>date('Y-m-d H:i:s',time())
);
????$result?=?Db::table('log_ip_ask')->insert($add_data);
if($result===false){
?????????show(10011,'限制次數(shù)寫(xiě)入記錄失??!');
}
????
return true;
}
/**
* 獲取客戶(hù)端IP地址
* @param integer $type 返回類(lèi)型 0 返回IP地址 1 返回IPV4地址數(shù)字
* @param boolean $adv 是否進(jìn)行高級(jí)模式獲?。ㄓ锌赡鼙粋窝b)
* @return mixed
*/
private function sys_get_client_ip($type = 0,$adv=false) {
$type = $type ? 1 : 0;
static $ip = NULL;
if ($ip !== NULL) return $ip[$type];
if($adv){
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
$pos = array_search('unknown',$arr);
if(false !== $pos) unset($arr[$pos]);
$ip = trim($arr[0]);
}elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
}elseif (isset($_SERVER['REMOTE_ADDR'])) {
$ip = $_SERVER['REMOTE_ADDR'];
}
}elseif (isset($_SERVER['REMOTE_ADDR'])) {
$ip = $_SERVER['REMOTE_ADDR'];
}
// IP地址合法驗(yàn)證
$long = sprintf("%u",ip2long($ip));
$ip = $long ? array($ip, $long) : array('0.0.0.0', 0);
return $ip[$type];
}
/**
* @desc php獲取當(dāng)前訪(fǎng)問(wèn)的完整url地址
* @return string
*/
private function sys_GetCurUrl() {
$url = 'http://';
if (isset ( $_SERVER ['HTTPS'] ) && $_SERVER ['HTTPS'] == 'on') {
$url = 'https://';
}
if ($_SERVER ['SERVER_PORT'] != '80') {
$url .= $_SERVER ['HTTP_HOST'] . ':' . $_SERVER ['SERVER_PORT'] . $_SERVER ['REQUEST_URI'];
} else {
$url .= $_SERVER ['HTTP_HOST'] . $_SERVER ['REQUEST_URI'];
}
return $url;
}
非法ip限制訪(fǎng)問(wèn):此處的限制一般用在服務(wù)器間的接口調(diào)用
// 允許訪(fǎng)問(wèn)的IP列表
private $ip_allow = array(
????????'192.168.0.111',
????????'192.168.0.112',
'192.168.0.113',
);
/**
* @desc 非法IP限制訪(fǎng)問(wèn)
* @param array $config
* @return bool
*/
private function illegalip(){
if(!$this->ip_limit){
return true;
}
$remote_ip = get_client_ip();
if(in_array($remote_ip, $ip_allow)){
return true;
}
return false;
}
傳輸安全HTTPS文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-702046.html
互聯(lián)網(wǎng)發(fā)展到今天,大家越來(lái)越重視自己的隱私,各大公司也越來(lái)越重視數(shù)據(jù)的安全。傳輸過(guò)程中的數(shù)據(jù)安全解決方案主要是“HTTPS”,能夠有效防止中間人攻擊等。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-702046.html
到了這里,關(guān)于PHP 如何設(shè)計(jì)一個(gè)高安全的電商平臺(tái):淘寶/京東商品類(lèi)API封裝接口的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!