1. 什麼是接口
接口簡單來說就是服務器端用來返回給其他程序或者客戶端數據的橋樑
2. 接口的作用
根據固定參數返回固定數據
3. API接口保障安全性原則
1.有調用者身份 2.請求的唯一性 3.請求的參數不能被篡改 4.請求的有效時間
4. 接口安全需求
1.最好必須啓用HTTPS 2.signature簽名 3.token登陸的唯一票據 4.驗證時間戳 5.對要求安全性高的接口數據進行加密傳輸(aes+rsa)
5. signature簽名
簡而言之,簽名設計的原則就是保證服務器所接收到的數據是自己的APP端傳過來的,而不是其他人非法調用的,在APP端給簽名加密時需要加上特有固定參數,服務器也是加上特有固定參數,從而來保證一對一的傳輸,每個接口都需要調用該簽名驗證方法
目的:
爲了提高傳參過程中,防止參數被惡意修改,在請求接口的時候加上sign可以有效防止參數被篡改
基本例子:
#接口 https://www.dong.com/api/product?&type=zl&p1=value1&p2=value2&p3=&sign=signValue #第一步: 拼接參數字符串,除去sign參數本身和爲空值的p3, 那麼剩下的就是字符串type=zl&p1=value1&p2=value2, 然後按參數名字符升(降)序, 得到字符串p1=value1&p2=value2&type=zl #第二步: 然後將參數名和值的字符串進行AES加密, 假設p1=value1&p2=value2&type=zl進行AES加密後的結果是abc123, 最終得到的字符串abc123就是參數sign的值signValue #第三步: 在接口中我們會接收到參數名sign的參數值abc123,然後解密, 再與接口中參數拼接排序後進行比較, 如果不一樣則說明參數的循序不一樣, 參數的值就一定是被修改過了。
高級例子:
基本例子因爲前端js暴露, 很容易被獲取AES的加密方式, 因而有效防止參數被篡改就變得很弱。 所以,我們何不在AES的加密key進行RSA加密。 第一步: 我們先在客戶端要產生一個random string(很重要,不能是單純的string) 對其進行RSA加密,然後把加密後的內容發送給後端, 第二步: 我們把random string跟傳遞的參數+(時間戳13位數)進行AES加密,發送給後端 第三步: 後端進行解密,判斷是否有改變傳遞的參數, 以及超過時間限制就不讓訪問,對sign進行cache緩存, 緩存中存在sign的就不讓訪問 RSA:非對稱加密算法,內容越大,解密時間越長 AES:對稱加密算法
代碼例子:
/** * [AesSecurity aes加密,支持PHP7.1] */class AesSecurity{ /** * [encrypt aes加密] * @param [type] $input [要加密的數據] * @param [type] $key [加密key] * @return [type] [加密後的數據] */ public static function encrypt($input, $key) { $data = openssl_encrypt($input, 'AES-128-ECB', $key, OPENSSL_RAW_DATA); $data = base64_encode($data); return $data; } /** * [decrypt aes解密] * @param [type] $sStr [要解密的數據] * @param [type] $sKey [加密key] * @return [type] [解密後的數據] */ public static function decrypt($sStr, $sKey) { $decrypted = openssl_decrypt(base64_decode($sStr), 'AES-128-ECB', $sKey, OPENSSL_RAW_DATA); return $decrypted; }}
用openssl生成rsa密鑰對(私鑰/公鑰):
openssl genrsa -out rsa_private_key.pem 2048openssl rsa -pubout -in rsa_private_key.pem -out rsa_public_key.pem
RSA:
header('Content-Type: text/plain;charset=utf-8');$data = 'phpbest';echo '原始內容: '.$data."\n";openssl_public_encrypt($data, $encrypted, file_get_contents(dirname(__FILE__).'/rsa_public_key.pem'));echo '公鑰加密: '.base64_encode($encrypted)."\n";$encrypted = base64_decode('nMD7Yrx37U5AZRpXukingESUNYiSUHWThekrmRA0oD0=');openssl_private_decrypt($encrypted, $decrypted, file_get_contents(dirname(__FILE__).'/rsa_private_key.pem'));echo '私鑰解密: '.$decrypted."\n";
6. token登陸的唯一票據
和PC登陸的session一樣,作爲用戶進入的唯一票據
因爲APP端沒有和PC端一樣的session機制,所以無法判斷用戶是否登陸,以及無法保持用戶狀態,所以就需要一種機制來實現session,這就是token的作用,token是用戶登陸的唯一票據,只要APP傳來的token和服務器端一致,就能證明你已經登陸
2、token設計時的種類:
(1)第三方登陸型:這種token形如微信的access_token,設計原理是按照OAuth2.0來的,其特點是定時刷新(比如兩小時刷新),目的是因爲數據源將登陸權限賦予第三方服務器時必須要控制其有效期和權限,要不然第三方服務器可以不經過用戶同意,無限期從數據源服務器獲取用戶任意數據
(2)APP自用登陸型:這種token就是一般的APP用的token,因爲不經過第三方,而是用戶直接取數據源服務器數據,所以設計比較隨意,只需要保證其token的唯一性就行
3、APP自用登陸型token實現步驟:
(1)數據庫用戶表添加token字段和time_out這個token過期時間點(不是時間段,即某個時間點)
(2)用戶登陸時(註冊時自動登陸也需要)生成一個token和過期時間存入表中
(3)在其他接口調用前,判斷token是否正確,正確則繼續,錯誤則讓用戶重新登陸
//token驗證方法,db::是數據庫操作類,這裏設置是token如果七天沒被調用則需要重新登陸 (也就是說用戶7天沒有操作APP則需要重新登陸), 如果某個接口被調用,則會重新刷新過期時間 public static function checktokens($token, $table) { $res = db::getOneForFields($table, 'time_out', 'token1 = ?', array($token)); if (!empty($res)) { if (time() - $res['time_out'] > 0) { return 90003; //token長時間未使用而過期,需重新登陸 } $new_time_out = time() + 604800;//604800是七天 if (db::setWhere($table, array('time_out' => $new_time_out), 'token1 = ?', array($token))) { return 90001; //token驗證成功,time_out刷新成功,可以獲取接口信息 } } return 90002; //token錯誤驗證失敗 }
原文:https://www.jianshu.com/p/86893f84710e