接口設計安全
引言
我的理解:接口簡單來說就是服務器端用來返回給其他程序或者客戶端數據的橋梁。
安全要求
1. 防止偽裝攻擊(不知明方調用接口)
2. 防止請求篡改(請求的參數被篡改)
3. 防止重復攻擊(請求被截獲,被再次惡意調用)
3. 防止數據泄露(如登陸、支付信息)
簽名驗證
1. 服務端分配客戶端特定的調用賬號信息:
AppID:調用方身份ID,接口提供方用此來識別調不同的調用者
App_secret:用於生成簽名sign
2. 接口調用方和接口提供方約定好統一的簽名加密算法
3. 接口調用必要傳入參數
參數名 | 類型 | 必選 | 描述 |
AppId | string | 是 | 調用方身份ID,接口提供方用此來識別調不同的調用者 |
paramet | mix | 否 | 請求參數 |
timestamp | int | 是 | 時間戳 |
sign | string | 是 | 一次接口調用的簽名值,服務器端 “防止 偽裝請求/防篡改/ 防重發” 識別的重要依據。 |
簽名算法過程
1. 對除簽名外的所有請求參數按key做的升序排列,value無需編碼。
(假設當前時間的時間戳是12345678,appid為 testid)
例如:調用接口 www.example.com/v1/user/edit?c=3&b=2&a=1×tamp=12345678
有c=3,b=2,a=1 三個參,另加上時間戳後, 按key排序後為:a=1,b=2,c=3,timestamp=12345678。
2. 把參數名和參數值連接成字符串,得到拼裝字符:a1b2c3timestamp12345678
3. 用申請到的appsecret 連接到接拼裝字符串頭部和尾部,然後進行32位MD5加密,最後將到得MD5加密摘要轉化成大寫。
示例:假設appkey=test256,strtouppermd5(test256a1b2c3timestamp12345678test256),取得MD5摘要值 C5F3EB5D7DC2748AED89E90AF00081E6 。
此時最終調用: www.example.com/v1/user/edit?c=3&b=2&a=1×tamp=12345678&appid=testid&sign=C5F3EB5D7DC2748AED89E90AF00081E6
服務端簽名驗證代碼
1 # 簽名的驗證方法代碼:
2 # $signtype ‘yes‘:驗證,‘no‘:不驗證
3
4 public function checkSign($args,$signature,$signtype = ‘yes‘)
5 {
6 if($signtype == ‘no‘) //上線時去除該部分,必須驗證簽名
7 {
8 return true;
9 }
10 if(!$args || !$signature)
11 {
12 return false;
13 }
14
15 //同一簽名調用時間限制,可以設定 20s,50s,300s,避免多次重復調用
16 if (time() - $args[‘timestamp‘] > 300)
17 {
18 return false;
19 }
20
21 //驗證 appid 身份合法性,根據appid查詢對應的 appsecret
22 $model=Model::where("appid=:appid")->find();
23 if($model){
24 $serverSecret=$model->appsecret;
25 }else{
26 return false;
27 }
28
29 //驗證簽名
30 ksort($args); //按數組的鍵排序
31 $sign = ‘‘;
32
33 foreach($args as $k => $v)
34 {
35 $sign .= $k . ‘=‘ . $v;
36 }
37 $sign = MD5($serverSecret.$sign.$serverSecret); //加密
38 if($sign == $signature)
39 {
40 return true;
41 }
42 return false;
43 }
總結:
- 接口調用方和接口提供方約定好統一的參數加密算法
- 接口調用方在調用時把加密後的_sign放在參數中去請求接口
- 接口提供方接到響應後,判斷時間戳是不是在有效時間內(這個時間間隔根據你的安全範圍可以是10分鐘,5分鐘,20秒等,過期失效,前提是需要保證接口提供方和調用方的服務器時間為準確的網絡同步時間)
- 把參數中除了_sign以外的參數進行加密,然後把加密結果和傳過來的_sign比較,相同則執行調用請求。
接口設計安全