1. 程式人生 > >一次性搞懂服務端API安全解決方案

一次性搞懂服務端API安全解決方案

今年五月份去融貝網、獵豹移動面試的時候,被問到API安全加密的問題,很慚愧,自己回答的很不全面。自己也知道那是沒有徹底弄明白原理。然後,8月份的時候,上家公司新專案啟動時也和同事探討過,然後就去徹徹底底瞭解了一下,趁著熱乎勁兒還沒過去總結出來吧。

安全是相對的,下面是根據安全級別分析。我用簡單的PHP程式碼演示出來,只是演示,程式碼寫的不嚴謹請輕噴啊!!!

1、完全開放的介面

這種我們稱之為“裸奔API”,只要連上網就能呼叫,不存在安全,一般只能查詢,不能執行增、刪、改的操作。

<?php

// 介面對外開放
public function noSecure($string)
{
	$data
= DB('table')->where('string', $string)->get(); if(!is_null($data)) { return $data; } } 複製程式碼

2、介面引數加密(基礎加密)

這種加密方式,只想讓特定的呼叫方使用。好比你把這些呼叫的人叫到一個小屋子,給他們宣佈說我這裡有個介面只打算給你們用,我給你們每人一把鑰匙,你們用的時候拿著這把鑰匙即可。

這把鑰匙就是我上文說到的引數加密規則,有了這個規則就能呼叫。

這有安全問題啊,這裡面的某個成員如果哪個不小心丟了鑰匙或者被人竊取,掌握鑰匙的人是不是也可以來掉用介面了呢?而且他可以複製很多鑰匙給不明不白的人用。

相當於有人拿到了你的請求連結,如果業務沒有對連結唯一性做判斷(實際上業務邏輯通常不會把每次請求的加密簽名記錄下來,所以不會做唯一性判斷),就會被重複呼叫,有一定安全漏洞,怎麼破?先看這個場景的程式碼,然後繼續往下看!

<?php

// 介面加密
public function secureBySign($string, $appKey, $sign)
{
	//檢驗簽名是否合法
	$string = $_POST("string");
	$appKey = $_POST("appKey");
	$sign = $_POST("sign");
	
	$signHelper = new SignHelper();
	$currentSign
= $signHelper->getSign($appKey, $string, ……); if($sign !== $currentSign) { return "簽名不合法"; } $data = DB('table')->where('string', $string)->get(); if(!is_null($data)) { return $data; } } 複製程式碼

3、介面引數加密+介面時效性驗證(一般達到這個級別已經非常安全了)

繼上一步,你發現有不明不白的人呼叫你的介面,你很不爽,隨即把真正需要呼叫介面的人又叫來,告訴他們每天給他們換一把鑰匙。和往常一樣,有個別夥伴的鑰匙被小偷偷走了,小偷煞費苦心,經過數天的踩點觀察,準備在一個月黑風高的夜晚動手。拿出鑰匙,搗鼓了半天也無法開啟你的神聖之門,因為小偷不知道你天天都在換新鑰匙。

小偷不服,經過一段時間琢磨,小偷發現了你們換鑰匙的規律。在一次獲得鑰匙之後,不加思索,當天就動手了,因為他知道他手裡的鑰匙在第二天你更換鑰匙後就失效了。

結果,小偷如願。怎麼破?先看這個場景的程式碼,然後繼續往下看!

<?php

// 介面加密並根據時間戳判斷有效性
public function secureBySignExpired($string, $appKey, $sign, $timestamp)
{
	//判斷請求是否過期---假設過期時間是20秒
	$requestTime = GetDateTimeByTicks($timestamp);
	if(($requestTime + 20) < $_SERVER["REQUEST_TIME"]) {
		return "介面過期";
	}
	
	//檢驗簽名是否合法
	$string = $_POST("string");
	$appKey = $_POST("appKey");
	$sign = $_POST("sign");
	
	$signHelper = new SignHelper();
	$currentSign = $signHelper->getSign($appKey, $string, ……);

	if($sign !== $currentSign) {
		return "簽名不合法";
	}
	
	$data = DB('table')->where('string', $string)->get();
	if(!is_null($data)) {
		return $data;
	}
}

複製程式碼

4、介面引數加密+時效性驗證+私鑰(達到這個級別安全性固若金湯)

繼上一步,你發現道高一尺魔高一丈,仍然有偷盜事情發生。咋辦呢?你打算下血本,給每個人配一把鑰匙的基礎上,再給每個人發個暗號,即使鑰匙被小偷弄去了,小偷沒有暗號,任然無法如願。即使小偷真正的如願,這樣也很容易定位是誰的暗號洩漏問題,找到問題根源,只需要給當前這個人換下鑰匙就行了,不用大動干戈。

但這個並不是萬無一失的,因為鑰匙和暗號畢竟還有可能被小偷搞到。程式碼如下:

<?php

// 介面加密並根據時間戳判斷有效性而且帶著私有key校驗
// 在呼叫介面時動態從庫裡取,每個呼叫方在呼叫時帶上他的appSecret,呼叫方一般把自己的appSecret放到網站或APP配置檔案中
public function secureBySignExpiredKeySecret($string, $appKey, $sign, $timestamp)
{
	//判斷請求是否過期---假設過期時間是20秒
	$requestTime = GetDateTimeByTicks($timestamp);
	if(($requestTime + 20) < $_SERVER["REQUEST_TIME"]) {
		return "介面過期";
	}

	// 根據appkey查庫獲取appSecret值
	$appSecret = DB('table')->where('appKey', $appKey)->get('appSecret');
	
	//檢驗簽名是否合法
	$string = $_POST("string");
	$appKey = $_POST("appKey");
	$sign = $_POST("sign");
	
	// 把appSecret加入進行加密
	$signHelper = new SignHelper();
	$currentSign = $signHelper->getSign($appKey, $appSecret, $string, ……);

	if($sign !== $currentSign) {
		return "簽名不合法";
	}
	
	$data = DB('table')->where('string', $string)->get();
	if(!is_null($data)) {
		return $data;
	}
}

複製程式碼

5、介面引數加密+時效性驗證+私鑰+Https(我把這個級別稱之為金鐘罩,世間最安全莫過於此)

安全第五層,在第四層的基礎上加HTTPS,關於HTTPS怎麼加,可以自行去了解,網上相關資料一堆。

關於加密演算法可以參考:Api介面加密策略