PHP 開發API接口簽名驗證
就安全來說,所有客戶端和服務器端的通信內容應該都要通過加密通道(HTTPS)傳輸,明文的HTTP通道將會是man-in-the- middle及其各種變種攻擊的溫床。所謂man-in-the-middle攻擊簡單講就是指惡意的黑客可以在客戶端和服務器端的明文通信通道上做手 腳,黑客可以監聽通信內容,偷取機密信息,甚至可以篡改通信內容,而通過加密後的通信內容理論上是無法被破譯的。
URL簽名生成規則
API的有效訪問URL包括以下三個部分: |
簽名算法如下:
1. 對所有請求參數進行字典升序排列; |
註意:請保證HTTP請求數據編碼務必為UTF-8格式,URL也務必為UTF-8編碼格式。
舉個實例:
PHP服務端先要給開發者(APP)分配一個appid與appsecret (正常情況下,開發者要到服務提供商的官網申請),作為客戶端,需要保留好官方頒發的appid & appsecret
appid會在請求中作為一個應用標識參與接口請求的參數傳遞,appsecret 將作為唯一不需要參數傳遞,但是它將作為驗證當前請求的關鍵參數,只有應用開發者和頒發的服務端才知道。由於簽名是依靠同樣的算法加密實現,因此,應用端和服務端可以計算出相同的簽名值,簽名實際意義在於服務端對客戶端的訪問身份認證。在某種意義上簽名機制有點類似用公鑰方法簽名,用每個應用對應的私鑰值來解密,只是這種解密過程實質就是核對簽名參數值的過程。
假設分配:
$appid=5288971;
$appsecret= ‘r5e2t85tyu142u665698fzu‘;
移動客戶端,需要請求服務列表(以下代碼可以為java或sf等移動端編寫)
請求地址: http://web.com/server/list
參數:
$array=[
‘appid‘=>5288971,
‘menu‘=>‘客戶服務列表‘,
‘lat‘=>21.223,
‘lng‘=>131.334
];
對應簽名算法
// 1. 對加密數組進行字典排序
foreach ($array as $key=>$value){
$arr[$key] = $key;
}
sort($arr); //字典排序的作用就是防止因為參數順序不一致而導致下面拼接加密不同
// 2. 將Key和Value拼接
$str = "";
foreach ($arr as $k => $v) {
$str = $str.$arr[$k].$array[$v];
}
//3. 通過sha1加密並轉化為大寫
//4. 大寫獲得簽名
$restr=$str.$appsecret;
$sign = strtoupper(sha1($restr));
將生產的sign簽名一起寫入array中,通過約定好的method方式發送參數到請求接口
$array[‘sign‘]=$sign;
打印$array
Array
(
[appid] => 5288971
[menu] => 客戶服務列表
[lat] => 21.223
[lng] => 131.334
[sign] => C096D7811E944386CE880597BA334A5AB640B088
)
客戶端將數據封裝xml或Json發送到服務端,服務端先解析
{"appid":5288971,"menu":"\u5ba2\u6237\u670d\u52a1\u5217\u8868","lat":21.223,"lng":131.334,"sign":"C096D7811E944386CE880597BA334A5AB640B088"}
$serverArray= json_decode($json,TRUE);
服務端查詢appid對應的密鑰
$model=Model::find()->where("appid=:appid")->params([":appid"=>$serverArray[‘appid‘]])->one();
if($model){
$serverSecret=$model->appsecret;
}
按照相同的字典排序與算法生成服務端的$sign ,判斷$sign 是否相同。
$clientSign=$array[‘sign‘];
unset($serverArray[‘sign‘]);
#生成服務端str
$serverstr = "";
foreach ($serverArray as $k => $v) {
$serverstr = $str.$k.$v;
}
$reserverstr=$str.$serverSecret;
$reserverSign = strtoupper(sha1($reserverstr));
if($clientSign!=$reserverSign){
die(‘非法請求‘);
}else{
// your code
continue;
}
在僅適用短信登錄做手機端app時,可以設置secret的過期時間,短信登錄後,保存appid(userid)與密鑰secret,每當用戶打開APP時,先聯網請求登錄是否過期,過期重新短信登錄獲取新的secret。
附加:
有時,我們使用hash_hmac進行加密(我們項目中使用……)
/*
* 生成簽名,$args為請求參數,$key為私鑰
*/
function makeSignature($args, $key)
{
if(isset($args[‘sign‘])) {
$oldSign = $args[‘sign‘];
unset($args[‘sign‘]);
} else {
$oldSign = ‘‘;
}
ksort($args);
$requestString = ‘‘;
foreach($args as $k => $v) {
$requestString .= $k . ‘=‘ . urlencode($v);
}
$newSign = hash_hmac("md5",strtolower($requestString) , $key);
return $newSign;
}
PHP 開發API接口簽名驗證