[toc]
# 接口常見的安全問題
* 數據篡改
* DOS攻擊/高頻請求
# 接口安全的解決策略
* 全參加密
* 一次性接口(記錄+超時)
# 代碼思路
```[sequence]
title:接口請求時序圖
participant APP as app
participant 服務器 as server
participant 服務器緩存 as cache
app->server: APP帶參數訪問服務器
note left of app: 檢查請求是否包含安全參數
server->server:參數中是否包含安全參數time
server-->app: 返回錯誤: 缺少安全參數 time!
server->server:參數中是否包含安全參數token
server-->app: 返回錯誤: 缺少安全參數 token!
note left of app: 確保接口請求的一次性
server->cache: 以token為鍵名查詢緩存的請求記錄
cache-->server: 返回請求記錄查詢結果
server-->app: 返回錯誤: 該接口已經請求過一次!
note left of app: 確保接口請求沒有超時
server->server: 請求時間戳和服務器時間戳比對
server-->app: 返回錯誤: 請求超時!
note left of app: 確保接口數據沒有篡改
server->server: 參數時間戳加密生成隨機字符串
server->server: 參數去除token后排序并加密, 生成token
server->server: 把參數中的token和服務器生成的token進行比對
server-->app: token不正確!
note left of app: 緩存接口請求記錄
server->cache: 把此次請求寫入緩存
server->cache: 清除緩存中超時的記錄
note left of app: 通過驗證
server->server: 進行下面的邏輯運算...
```
# 代碼示例(python2)
```python
# 建立token緩存, 實現接口一次性處理
token_cache_dict = dict()
# 構造返回數據
private_key = 'public_bike_project'
response_data = dict()
response_data['data'] = dict()
# 獲取post過來的參數
post_dicts = self.request.body_arguments
post_dict = dict()
for k, v in post_dicts.items():
post_dict[k] = v[0]
# 判斷是否有time和token這兩個關鍵參數
if not post_dict.has_key('time'):
response_data['ret'] = 2
response_data['data']['msg'] = '缺少安全參數 time!'
self.write(json.dumps(response_data))
return False
if not post_dict.has_key('token'):
response_data['ret'] = 2
response_data['data']['msg'] = '缺少安全參數 token!'
self.write(json.dumps(response_data))
return False
# 如果有, 把這兩個關鍵參數存起來
app_time = post_dict['time']
app_token = post_dict['token']
# 接口一次性認證(緩存中是否有相同token)
if self.token_cache_dict.has_key(app_token):
response_data['ret'] = 2
response_data['data']['msg'] = '該接口已經請求過一次!'
self.write(json.dumps(response_data))
return False
# 獲取服務器毫秒級時間戳, 用于比對接口請求是否超時
server_time = int(round(time.time() * 1000))
# 判斷請求是否超時(300秒)
if (server_time - int(app_time)) > 300000:
response_data['ret'] = 1
response_data['data']['msg'] = '請求超時!'
self.write(json.dumps(response_data))
return False
# 生成隨機字符串, 生成token時要用
noncestr = self.make_sign(self.make_sign(app_time) + private_key)
# 取出token
app_token = post_dict['token']
post_dict.pop('token')
# 所有參數排序后加key, md5
pre_str = self.sort_data(post_dict)
str_for_token = pre_str + "&key=" + noncestr
server_token = self.make_sign(str_for_token)
# 根據參數生成token, 比對token
if app_token != server_token:
response_data['ret'] = 2
response_data['data']['msg'] = 'token不正確!'
self.write(json.dumps(response_data))
return False
# 最終驗證通過, 把token緩存中超時的token去掉, 并把本次token加入token緩存
server_time = int(round(time.time() * 1000))
for k, v in self.token_cache_dict.items():
if (server_time - v) > 300000:
del self.token_cache_dict['k']
# 請求沒有問題, 把此次請求記錄寫入緩存
self.token_cache_dict[app_token] = server_time
return True
```
# 擴展閱讀
* [API接口安全性設計](https://www.jianshu.com/p/c6518a8f4040)
- 打造高逼格接口管理平臺
- 開篇
- 課程簡介
- 聊聊接口平臺
- 接口平臺簡介
- 優雅的使用看云
- 接口和markdown
- 接口文檔版本演進
- 微軟的硬菜--vscode
- markdown基礎語法
- markdown進階語法--流程圖
- markdown進階語法--時序圖
- markdown進階語法--API文檔
- 接口文檔的基本概念
- 接口管理平臺的基本元素
- 編寫接口文檔并且發布更新
- 接口安全
- 文檔安全
- 接口安全
- Git化你的文檔
- 使用Git管理文檔
- 自動化
- 自動化文檔更新
- 收尾
- 如何反饋問題
- 課程總結
- 示例
- 更新信息
- 查詢歷史天氣
- markdown語法示例
- 流程圖示例
- 時序圖示例
- 登錄/注冊
- 數據字典示例
- 課程問題解答