前言
在Web開發中瀏覽器與伺服器進行通訊,在伺服器端我們可以用"session"來確定使用者的身份,然後根據從瀏覽器接收到的引數,伺服器返回給瀏覽器相應的資料。但是在移動端與伺服器進行通訊時,並沒有"session"的存在(也許是我不知道),不過我們可以要求移動端提交引數的時候把使用者的"id"或"Guid"和其他引數一起提交過來。然後根據請求的引數來返回對應的內容.
那麼問題來了,我可以使用抓包工具獲取別人提交"url地址"與"引數",然後進行模擬操作,我就可以獲取該使用者的全部資料,如果涉及到金錢的話,更是一場毀滅性的災難。所以,在開始一個移動端的專案前,加密驗證是最先考慮與準備的事情.
畢竟誰也不希望,有人可以在自己家裡面隨意的進進出出!
一、介面分類
在我們日常接觸的app中,像"登入","註冊","找回密碼"這種沒有登入的情況下,都可以訪問的介面,我們稱為"通用介面",像"個人資訊","支付密碼",這種涉及到個人隱私或者金錢的介面,我們稱為"非通用介面",再次重複一下,介面分為
1.通用介面 // 加密程度略低於非通用介面,但必須要做加密
2.非通用介面 // 必須是你知道的最安全的加密方式
附上程式碼
private static $verify;
// Verify 為注入檔案
public function __construct(Verify $verify)
{
self::$verify = $verify;
}
private function verify($request)
{
if($request->path()=='login'){
// 通用方法
return self::$verify->common($request);
}else{
// 非通用方法
return self::$verify->proprietary($request);
}
return false;
}
public function handle($request, Closure $next)
{
$time = time();
// 此處呼叫上邊的verify方法,根據返回的狀態碼,來返回移動端資訊提示
switch($this->verify($request))
{
case "SN200":
$temp = $next($request);
return $temp;
break;
//最後在完善其他狀態碼資訊
}
}
下面我們看看訪問 login 路由時, 通用方法都做了什麼?
public function common($request)
{
// 接收request物件
if($request->all()){
$data = $request->all();
// 時間驗證
// $data['time']為移動端當前時間戳
$ckTime = $this->checkTime($data['time']);
// SN002 請求超時
if(!$ckTime) return 'SN002';
// 驗證ID的存在
// SN004 使用者沒有登入
if(!isset($data['id'])) return 'SN004';
// 根據移動端傳遞的版本號來進行加密驗證
switch ($data['version']){
case $data['version'] >'1.4' && $data['version']<'2.0':
// 開始進行通用加密驗證
$temp = $this->checkCommon_v1($request);
break;
default:
$temp = $this->checkCommon_v2($request);
break;
}
if($temp){
// SN200 驗證通過
return "SN200";
}
// SN005 簽名錯誤
return "SN005";
}
// 伺服器有請求,但引數為空,通常與安卓和ios的框架有關係(需注意)
return false;
}
程式碼與註解:
-
時間驗證
public function checkTime($time) { $Time_difference = abs(time()-$time); if($Time_difference>30){ return false; } return true; }
請求到達伺服器的時間減去移動端本地的時間戳, 如果大於
30
秒, 就代表請求超時,有可能是該使用者的網路不算太好。如果不使用abs()
函式的話,萬一我的資料包被別人抓住了他可以無限大的修改$time
這個值,那麼使用伺服器時間戳去相減的到的一直是負數,還是小於30
秒的。由此可見使用abs()
函式會更加的安全一些。 - 驗證
ID
的存在
主要是為接下來的非通用介面驗證做準備。通用介面的
ID
可以與移動端事前定義一個值。"移動端與服務端ID的值一定要相同,要不然沒辦法做接下來的驗證"
- 根據移動端傳遞的版本號來進行加密驗證
每個大版本的改變,加密的方式都應隨著改變而改變。小版本的修正就沒有必要去更換加密方式了。
-
通用加密驗證
private function checkCommon_v1($request) { $data = $request->all(); $path = $request->path(); $time = $data['time']; $id = '1'; $param = $data['param']; $cryptToken = "JRzhang"; $signature = md5($path.$time.$id.$param.$cryptToken); if($signature!=$data['signatures']){ return false; }else{ return true; } }
這裡說一下移動端應傳遞的引數
time 移動端當前時間
param 真正的請求引數 陣列轉為json後的字串
version 移動端當前版本
deviceid 裝置唯一識別碼(非通用介面使用,用於單點登入)
signature 簽名移動端應按照上邊的引數順序進行MD5加密
cryptToken 移動端儲存一份與伺服器端相同,但不進行引數傳遞只做加密使用
坑點: 伺服器對 android
進行介面除錯時,一定要注意 android
本地的時間戳。因為android
手機可以tmd
調整本地時間.
最後如果移動端傳遞的signature
與伺服器端生成的$signature
相同, 那麼恭喜你,你可以從我家的大門進來了, 但只可以在院子裡轉一轉, 如果想進屋裡,請繼續關注