原創聲明:本文為作者原創,未經允許不得轉載,經授權轉載需注明作者和出處
1:微信服務器A與小程序B之間的數據傳輸
2:小程序B與自己服務器C之間的數據傳輸
3:微信服務器A與自己服務器C之間的數據傳輸
正常來說,數據從A傳輸到B,再到C,ABC三點的數據都是一樣的。
但也許是不一致的,比如:
1:http傳輸過程中因為軟件或硬件問題造成數據丟失一部分。
2:黑客攔截數據、修改數據、繼續發送數據。
3:等等等
如果不做任何措施,從B發出數據data,傳輸過程中“丟失部分數據”或”被黑客修改數據”,然后C接收到數據data2
在C不知道接收的數據data2是否和B發出的數據data是否一致,
如果把不一致的數據當做正確的數據繼續操作,將會出現各種安全性的問題。
為了讓C知道:接收的數據是否和B發出的數據是否一致,所以采取了簽名的機制。
數據完整、安全的重要性:
比如:你去銀行取錢,營業員從“遠程服務器”查詢你的“賬戶余額”。
“遠程服務器”發送過來1000元,你讓“同伙”劫持數據,把這1000元改成5000元,并發送給營業員。如果此時沒有做數據完整性校驗,營業員收到你的余額就是5000元,他就給你5000元。本來你余額為1000元,結果給你5000元。
這僅僅是一個例子,在不同的應用場合,如果不做數據完整性校驗,會出現各種問題。
所以,數據的安全、完整性很重要,所以敏感的數據必須做簽名驗證。
上圖中
BC之間傳輸為例,說明具體數據傳輸過程:一:BC先約定好三點:
1:“簽名算法”
2:“密鑰”(一般是隨機生成復雜的字符串)
3:“算法參數的組裝規則”(簡稱’參規’)
(為了防止密鑰的泄露,此密鑰僅用于本地,不能在網絡傳輸,以防劫持)
二:在B執行:簽名算法( 參規(原始數據,密鑰) )=簽名
三:從B發出“原始數據”和“簽名”到C
四:網絡傳輸過程(安全的或者數據丟失或者黑客劫持)
五:C接收到“待定數據”和“簽名”
六:在C執行:簽名算法( 參規(待定數據,密鑰) )=新簽名
判定:
1:如果接收的簽名=新簽名,就說明數據完整、安全(待定數據=原始數據)
2:如果接收的簽名!=新簽名,說明待定數據異常、不安全(待定數據!=原始數據)
由上邊可知:小程序和開發者的三點約定為:
1:簽名算法為:sha1
2:密鑰為:session_key
3:算法參數的組裝規則:“原始數據字符串”連接“密鑰字符串”
(注:小程序用的規則如上,比較簡單。還可以隨意約定規則,比如:數據+密鑰+*#abc等)所以小程序生成簽名的公式:
sha1(原始數據+session_key)=signutrue
注:官方文檔中的rawData指的就是“原始數據”,raw英文為“原始的,未被加工的意思”
在B:簽名算法(數據+密鑰)=簽名,發出“數據”、”簽名”
傳輸過程:”數據”沒變,“簽名”沒變
在C:簽名算法(數據+密鑰)=簽名
結果:簽名==簽名,可以判定數據安全
在B:簽名算法(數據+密鑰)=簽名,發出“數據”、”簽名”
傳輸過程:黑客修改了”數據”變為”數據2”,“簽名”沒變
在C:簽名算法(數據2+密鑰)=簽名2
結果:簽名!=簽名2,可以判定數據不安全
在B:簽名算法(數據+密鑰)=簽名,發出“數據”、”簽名”
傳輸過程:黑客修改了”簽名”變為”簽名2”,“數據”沒變
在C:簽名算法(數據+密鑰)=簽名
結果:簽名2!=簽名,可以判定數據不安全
在B:簽名算法(數據+密鑰)=簽名,發出“數據”、”簽名”
傳輸過程:黑客修改了”數據和簽名”變為”數據2和簽名2”
在C:簽名算法(數據2+密鑰)=簽名3
結果:簽名2和簽名3有幾率相等,什么情況下相等呢?
因為在C,簽名算法(數據2+密鑰)=簽名3
只有黑客獲取密鑰,在傳輸過程中也執行,簽名算法(數據2+密鑰)=簽名2
簽名2才等于簽名3。
因為為了防止密鑰的泄露,此密鑰僅用于本地,不在網絡傳輸,所以黑客無法獲取密鑰。
結果:簽名2!=簽名3,可以判定數據不安全。
B1的簽名相關數據為:
1:rawData
2:signature
"{"nickName":"三石","gender":1,"language":"en","city":"Liaocheng","province":"Shandong","country":"CN",
"avatarUrl":"http://wx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTJX1ic14jrA6pbgCw2r8PxlmOtAr5zlvE4icfvwRvelsFAya13PscYatzERE29wia7A1R53fy3QwJxgg/0"}"
rawData的數據僅包含基本信息的數據,userInfo內的信息永遠是保持一致的。
只是格式不一樣,一個是JSON字符串,一個是對象。
在微信服務器簽名signature的生成過程為:
signature=sha1(rawData,session_key)
所以signature只能保證基本信息的數據完整性和安全性。
**encryptedData與iv也需要單獨的檢驗數據完整性
具體方法見此文:
8:用戶敏感信息完整性檢驗(加解密、簽名系列)
通常是在自己服務器后臺做驗證通常是在自己服務器后臺做驗證
小程序調用wx.getUserInfo()時,微信服務器
通過原始數據,session_key生成簽名發送給小程序。
即:sha1( 原始數據+ session_key )=signature
1:先獲取session_key(傳送門)
2:把小程序端調用wx.getUserInfo()獲取數據中的 rawData(原始數據)、signature,用wx.request()發送到自己的服務器。
3:在服務器后臺,接收傳送來的rawData(原始數據)、signature。使用相同的算法計算出簽名signature2
即:sha1( rawData+ session_key )=signature2
結果:
比對 signature 與 signature2 即可校驗數據的完整性。
由官方文檔知道:
sha1( rawData+ session_key )=signature
即sha1的參數為:rawData字符串“連接”sesson_key字符串。
如wx.getUserInfo的數據校驗:
接口返回的rawData:{
"nickName": "Band",
"gender": 1,
"language": "zh_CN",
"city": "Guangzhou",
"province": "Guangdong",
"country": "CN",
"avatarUrl": "http://wx.qlogo.cn/mmopen/vi_32/1vZvI39NWFQ9XM4LtQpFrQJ1xlgZxx3w7bQxKARol6503Iuswjjn6nIGBiaycAjAtpujxyzYsrztuuICqIM5ibXQ/0"
}
用戶的 session-key:
HyVFkGl5F5OQWJZZaNzBBg==
所以,用于簽名的字符串為:{
"nickName": "Band",
"gender": 1,
"language": "zh_CN",
"city": "Guangzhou",
"province": "Guangdong",
"country": "CN",
"avatarUrl": "http://wx.qlogo.cn/mmopen/vi_32/1vZvI39NWFQ9XM4LtQpFrQJ1xlgZxx3w7bQxKARol6503Iuswjjn6nIGBiaycAjAtpujxyzYsrztuuICqIM5ibXQ/0"
}HyVFkGl5F5OQWJZZaNzBBg==
使用sha1得到的結果為:75e81ceda165f4ffa64f4068af58c64b8f54b88c
<button bindtap="tap">tap</button>
Page({
tap: function () {
//調用登錄接口
wx.login({
success: function (login) {
//成功,返回登錄憑證js_code
var js_code = login.code;
//調用獲取用戶信息接口
wx.getUserInfo({
success: function (res) {
//獲取原始數據
var rawData = res.rawData;
//獲取簽名
var signature = res.signature;
//調用網絡請求接口,把數據發送給服務器
wx.request({
url: 'http://www.yoururl.com/test.php',
data: {
js_code: js_code, //js_code用戶獲取session_key
rawdata: rawData, //原始數據
signature: signature, //簽名
},
method: 'GET', //用Get的請求方式
header: {
'content-type': 'application/json'
},
success: function (data) {
//成功,返回signature,signature2數據
console.log(data);
}
})
}
})
}
});
}
})
<?php
/*1:獲取session_key********************************/
//AppID(小程序ID)
$APPID= "wx138cb91a9900af75";
//AppSecret(小程序密鑰)
$SECRET = "0d082ea09511df65ef3f2300fdbe0147";
//接收小程序端發來的js_code
$js_code = $_GET[js_code];
//小程序接口(appid+secret+js_code=sessionId+openId)
$url = "https://api.weixin.qq.com/sns/jscode2session?appid={$APPID}&secret={$SECRET}&js_code={$js_code}&grant_type=authorization_code";
//模擬網頁的GET請求
$timeout = 5;
$ch = curl_init(); //初始化curl
curl_setopt($ch, CURLOPT_URL, $url); //設置訪問的url地址
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //參數為1表示傳輸數據,為0表示直接輸出顯示。
curl_setopt($ch, CURLOPT_HEADER, 0); //參數為0表示不帶頭文件,為1表示帶頭文件
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); //獲取https需要加上此
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); //獲取https需要加上此
$json_data = curl_exec($ch); //執行命令并把獲取的數據賦值給$output
curl_close($ch); //關閉URL請求
//返回的Json數據轉換成php對象
$obj = json_decode($json_data);
//獲得session_key
$session_key =$obj->session_key;
/*2:校驗數據有效性********************************/
//獲取小程序發送來的簽名signature
$signature = $_GET['signature'];
//獲取小程序發送來的原始數據rawData
$rawdata = $_GET['rawdata'];
//生成signature2
$signature2 = sha1($rawdata.$session_key);
//生成鍵值對數組,用于轉換為Json數組發送給小程序
$arr = ["signature"=>$signature,"signature2"=>$signature2];
//鍵值對數組轉換為json數組
$arr_json = json_encode($arr);
//發送給小程序,在wx.request()的sucess方法接收
echo $arr_json;
?>