Sign簽名生成與校驗
大家先思考一個問題: 你在寫開放的API接口時是如何保證數據的安全性的?
先來看看有哪些安全性問題在開放的api接口中,我們通過http Post或者Get方式請求服務器的時候,會面臨着許多的安全性問題,例如:
-
請求來源(身份)是否合法?
-
請求參數被篡改?
-
請求的唯一性(不可復制)
解決方案:為了保證數據在通信時的安全性,我們可以采用參數簽名的方式來進行相關驗證。
案列分析
我們通過給某 [移動端(app)] 寫 [后台接口(api)] 的案例進行分析:
客戶端:以下簡稱app
后台接口:以下簡稱api
我們通過app查詢產品列表這個操作來進行分析:
app中點擊查詢按鈕》調用api進行查詢》返回查詢結果==>顯示在app中
一、不進行驗證的方式
api查詢接口:
app調用:http://api.test.com/getproducts?參數1=value1.......
如上,這種方式簡單粗暴,通過調用getproducts方法即可獲取產品列表信息了,但是這樣的方式會存在很嚴重的安全性問題,沒有進行任何的驗證,大家都可以通過這個方法獲取到產品列表,導致產品信息泄露。
那么,如何驗證調用者身份呢?如何防止參數被篡改呢?
二、MD5參數簽名的方式
我們對api查詢產品接口進行優化:
1.給app分配對應的key、secret
2.Sign簽名,調用API 時需要對請求參數進行簽名驗證,簽名方式如下:
a. 按照請求參數名稱將所有請求參數按照字母先后順序排序得到:keyvaluekeyvalue...keyvalue 字符串如:將arong=1,mrong=2,crong=3 排序為:arong=1, crong=3,mrong=2 然后將參數名和參數值進行拼接得到參數字符串:arong1crong3mrong2。
b. 將secret加在參數字符串的頭部后進行MD5加密 ,加密后的字符串需大寫。即得到簽名Sign
新api接口代碼:
app調用:http://api.test.com/getproducts?key=app_key&sign=BCC7C71CF93F9CDBDB88671B701D8A35&參數1=value1&參數2=value2.......
注:secret 僅作加密使用, 為了保證數據安全請不要在請求參數中使用。
如上,優化后的請求多了key和sign參數,這樣請求的時候就需要合法的key和正確簽名sign才可以獲取產品數據。這樣就解決了身份驗證和防止參數篡改問題,如果請求參數被人拿走,沒事,他們永遠也拿不到secret,因為secret是不傳遞的。再也無法偽造合法的請求。
但是...這樣就夠了嗎?細心的同學可能會發現,如果我獲取了你完整的鏈接,一直使用你的key和sign和一樣的參數不就可以正常獲取數據了...-_-!是的,僅僅是如上的優化是不夠的。。。。。。
請求的唯一性:
為了防止別人重復使用請求參數問題,我們需要保證請求的唯一性,就是對應請求只能使用一次,這樣就算別人拿走了請求的完整鏈接也是無效的。
唯一性的實現:在如上的請求參數中,我們加入時間戳:timestamp(yyyyMMddHHmmss),同樣,時間戳作為請求參數之一,也加入sign算法中進行加密。
新的api接口:
app調用:
http://api.test.com/getproducts?key=app_key&sign=BCC7C71CF93F9CDBDB88671B701D8A35×tamp=201603261407&參數1=value1&參數2=value2.......
如上,我們通過timestamp時間戳用來驗證請求是否過期。這樣就算被人拿走完整的請求鏈接也是無效的。
Sign簽名安全性分析:
通過上面的案例,我們可以看出,安全的關鍵在於參與簽名的secret,整個過程中secret是不參與通信的,所以只要保證secret不泄露,請求就不會被偽造。
總結
上述的Sign簽名的方式能夠在一定程度上防止信息被篡改和偽造,保障通信的安全,這里使用的是MD5進行加密,當然實際使用中大家可以根據實際需求進行自定義簽名算法,比如:RSA,SHA等加密算法。
1:sign驗證法:
這種驗證方式,一般過程是:
第一:給你一個【私鑰】[app_secret] 和[app_id]
第二:你要提交的所有數據都需要提供sign簽名。
第三:sign簽名的獲取方式。
例如:給用戶id為99的人增加100積分:
$app_id = 'Te001';
$secret = 'e10adc3949ba59abbe56e057f20f883e';
$url = 'http://127.0.0.1/test/apiDataCheck';
$post = array(
'user_id' => 99,
'point' => 100
);
function addSign($url, $data){
$str = '';
$data['app_id'] = $app_id;
ksort($data);
foreach($data as $k => $v){
$str .= $k.'='.$v.'&';
}
$str = substring($str, 0, -1);
$str = $url.'?'.$str.$secret;
$data['sign'] = md5($str);
return $data;
}
curl_post($url, addSign($post));
addSign 就是一個sign的獲取方式:所有數據加上app_id,字段順序排序,以get參數方式連接。然后url+?+get參數+私鑰,進行md5加密獲取sign簽名。進而進行接口調用。
第四:服務器端驗證數據合法性。
接口在操作數據之前,首先按照原本既定的sign生成方式,驗證sign合法性,進而進行下一步操作。
sign生成的兩種方式:
-
在前端直接用密鑰生成sign,后端用相同的密鑰驗證。
-
前端先將需要請求的參數調用一個api接口,后端生成sign傳給前端,前端再拿sign加參數區請求后端,后端再用之間api接口生成的sign驗證。
2:token法:
token法的步驟大概是:
1:給你一個app_id和app_secret。
2:提供一個利用app_id和app_secret獲取token的接口。
3:token的時效性設定。
4:獲取token接口的使用次數限制。
1:獲取token
$app_id = 'Token001';
$app_secret = 'e10adc3949ba59abbe56e057f20f883e';
$url = 'http://127.0.0.1/token/getToken?app_id='.$app_ip.'&app_secret='.$app_secret;
$token = curl_get($url);
// $token = array(
// 'token' => 'e10adc3949ba59abbe56e057f20f883e',
// 'expire' => '1444444400'
// );
session('token', $token['token']);
session('expire', $token['expire']);
2:接口調用
$url = 'http://127.0.0.1/token/getUserInfo';
$post['user_id'] = 1;
if(time() < session('expire')){
$post['user_id'] = 1;
$post['token'] = session('token');
}else{
步驟1:
}
$userInfo = curl_post($post);
5:服務器驗證token:
Token原理以及應用
一、token的優勢
1.無狀態、可擴展
在客戶端存儲的Tokens是無狀態的,並且能夠被擴展。基於這種無狀態和不存儲Session信息,負載負載均衡器能夠將用戶信息從一個服 務 傳到其他服務器上。
如果我們將已驗證的用戶的信息保存在Session中,則每次請求都需要用戶向已驗證的服務器發送驗證信息(稱為Session親和性)。用戶量大時,可能會造成 一些擁堵。但是不要着急。使用tokens之后這些問題都迎刃而解,因為tokens自己hold住了用戶的驗證信息。
2.安全性
請求中發送token而不再是發送cookie能夠防止CSRF(跨站請求偽造)。即使在客戶端使用cookie存儲token,cookie也僅僅是一個存儲機制而不是用於認證。不將信息存儲在Session中,讓我們少了對session操作。
token是有時效的,一段時間之后用戶需要重新驗證。我們也不一定需要等到token自動失效,token有撤回的操作,通過token revocataion可以使一個特定的token或是一組有相同認證的token無效。
3.可擴展性
Tokens能夠創建與其它程序共享權限的程序。例如,能將一個隨便的社交帳號和自己的大號(Fackbook或是Twitter)聯系起來。當通過服務登錄Twitter(我們將這個過程Buffer)時,我們可以將這些Buffer附到Twitter的數據流上(we are allowing Buffer to post to our Twitter stream)。
使用tokens時,可以提供可選的權限給第三方應用程序。當用戶想讓另一個應用程序訪問它們的數據,我們可以通過建立自己的API,得出特殊權限的tokens。
4.多平台跨域
我們提前先來談論一下CORS(跨域資源共享),對應用程序和服務進行擴展的時候,需要介入各種各種的設備和應用程序。
Having our API just serve data, we can also make the design choice to serve assets from a CDN. This eliminates the issues that CORS brings up after we set a quick header configuration for our application.
只要用戶有一個通過了驗證的token,數據和資源就能夠在任何域上被請求到。
Access-Control-Allow-Origin: *
5.基於標准
創建token的時候,你可以設定一些選項。我們在后續的文章中會進行更加詳盡的描述,但是標准的用法會在JSON Web Tokens體現。
最近的程序和文檔是供給JSON Web Tokens的。它支持眾多的語言。這意味在未來的使用中你可以真正的轉換你的認證機制。
二、Token的原理
1.將荷載payload,以及Header信息進行Base64加密,形成密文payload密文,header密文。
2.將形成的密文用句號鏈接起來,用服務端秘鑰進行HS256加密,生成簽名.
3.將前面的兩個密文后面用句號鏈接簽名形成最終的token返回給服務端
注:
(1)用戶請求時攜帶此token(分為三部分,header密文,payload密文,簽名)到服務端,服務端解析第一部分(header密文),用Base64解密,可以知道用了什么算法進行簽名,此處解析發現是HS256。
(2)服務端使用原來的秘鑰與密文(header密文+"."+payload密文)同樣進行HS256運算,然后用生成的簽名與token攜帶的簽名進行對比,若一致說明token合法,不一致說明原文被修改。
(3)判斷是否過期,客戶端通過用Base64解密第二部分(payload密文),可以知道荷載中授權時間,以及有效期。通過這個與當前時間對比發現token是否過期。
三,實現思路
1.用戶登錄校驗,校驗成功后就返回Token給客戶端。
2.客戶端收到數據后保存在客戶端
3.客戶端每次訪問API是攜帶Token到服務器端。
4.服務器端采用filter過濾器校驗。校驗成功則返回請求數據,校驗失敗則返回錯誤碼