數據安全(反爬蟲)之「防重放」策略

大前端時代的安全性一文中講了 Web 前端和 Native 客戶端如何從數據安全層面作反爬蟲策略,本文接着以前的背景,將從 API 數據接口的層面講一種技術方案,實現數據安全。前端

1、 API 接口請求安全性問題

API 接口存在不少常見的安全性問題,常見的有下面幾種狀況git

  1. 即便採用 HTTPS,諸如 Charles、Wireshark 之類的專業抓包工具能夠扮演證書頒發、校驗的角色,所以能夠查看到數據
  2. 拿到請求信息後原封不動的發起第二個請求,在服務器上生產了部分髒數據(接口是背後的邏輯是對 DB 的數據插入、刪除等)

因此針對上述的問題也有一些解決方案:程序員

  1. HTTPS 證書的雙向認證解決抓包工具問題
  2. 假如經過網絡層高手截獲了 HTTPS 加證書認證後的數據,因此須要對請求參數作簽名
  3. 「防重放策略」解決請求的屢次發起問題
  4. 請求參數和返回內容作額外 RSA 加密處理,即便截獲,也沒法查看到明文。

關於 HTTPS 證書雙向認證和 Web 端反爬蟲技術方案均在大前端時代的安全性一文中有具體講解。接下來引出本文主角:防重放github

2、 請求參數防篡改

在以前的文章也講過,HTTPS 依舊能夠被抓包,形成安全問題。抓包工具下數據依舊是裸奔的,能夠查看Charles 從入門到精通文中講的如何獲取 HTTPS 數據。算法

假如經過網絡層高手截獲了 HTTPS 加證書認證後的數據,因此須要對請求參數作簽名。步驟以下數據庫

  • 客戶端使用約定好的密鑰對請求參數進行加密,獲得簽名 signature。並將簽名加入到請求參數中,發送給服務端
  • 服務端接收到客戶端請求,使用約定好的密鑰對請求參數(不包括 signature)進行再次簽名,獲得值 autograph
  • 服務器對比 signature 和 autograph,相等則認爲是一次合法請求,不然則認爲參數被篡改,斷定爲一次非法請求

由於中間人不知道簽名密鑰,因此即便攔截到請求,修改了某項參數,可是沒法獲得正確的簽名 signature,這樣構造的一個請求,會被服務器斷定爲一次非法請求。segmentfault

3、 防重放策略

在工程師文化中,咱們要作一個事情,就首先要對這個事情下個定義。咱們才能知道作什麼、怎麼作。緩存

理論上,一個 API 接口請求被收到,服務會作校驗,可是當一個合法請求被中間人攔截後,中間人原封不動得重複發送該請求一次或屢次,這種重複利用合法請求進行得攻擊被成爲重放安全

重放會形成服務器問題,因此咱們須要針對重放作防重放。本質上就是如何區別去一次正常、合法的請求。服務器

3.1 基於 timestamp 的方案

理論上,客戶端發起一次請求,到服務端接收到這個請求的時間,業界斷定爲不超過60秒。利用這個特徵,客戶端每次請求都加上 timestamp1,客戶端將 timestamp1 和其餘請求參數一塊兒簽名獲得 signature,以後發送請求到服務器。

  • 服務器拿到當前時間戳 timestamp2,timestap2 - timestamp1 > 60s,則認爲非法
  • 服務端接收到客戶端請求,使用約定好的密鑰對請求參數(不包括 signature、timestamp1)進行再次簽名,獲得值 autograph。比對 signature 和 autograph,若不相等則認爲是一次非法請求

假如中間人攔截到請求,修改了 timestamp 或者其餘的任何參數,可是不知道密鑰,因此服務器依舊斷定爲非法請求。 中間人從抓包、篡改參數、發起請求的過程通常來講大於60秒,因此服務器依舊會斷定爲非法請求。

基於 timestamp 的設計缺陷也很明顯,種種緣由下,60秒內的請求,會鑽規則漏洞,服務器斷定爲一次合法請求。

3.2 基於 nonce 的方案

既然時間戳會有漏洞,那麼新方案是基於隨機字符串 nonce。也就是說每次請求都加入一個隨機字符串,而後將其餘參數一塊兒利用密鑰加密獲得簽名 signature。服務端收到請求後

  • 先判斷 nonce 參數是否能存在於某個集合中,若是存在則認爲是非法請求;若是不存在,則將 nonce 添加到當前的集合中
  • 服務端將客戶端請求參數(除 nonce)結合密鑰加密獲得 autograph,將 signature 和 autograph 比對,不相等則認爲非法請求

可是該方案也有缺點,由於當次的請求都須要和集合中去搜索匹配,因此該集合不能太大,否則匹配算法特別耗時,接口性能下降。因此不得不按期刪除部分 nonce 值。可是這樣的狀況下,被刪除的 nonce 被利用爲重放攻擊,服務器斷定爲合法請求。

假設服務器只保存24小時內請求的 nonce,該存儲仍舊是一筆不小的開銷。

3.3 基於 timestamp + nonce 的方案

根據 timestamp 和 nonce 各自的特色:timestamp 沒法解決60秒內的重放請求;nonce 存儲和查找消耗較大。因此結合2者的特色,便有了 「timestamp + nonce 的防重放方案」。

  • 利用 timestamp 解決超過60秒被認爲非法請求的問題
  • 利用 nonce 解決 timestamp 60秒內的漏網之魚

步驟:

  1. 客戶端將當前 timestamp一、隨機字符串和其餘請求參數,按照密鑰,生成簽名 signature
  2. 服務端收到請求,利用服務端密鑰,將除 timestamp一、隨機字符串以外的請求參數,加密生成簽名 autograph
  3. 服務端對比 signature 和 autograph,不相等則認爲非法請求
  4. 拿到服務端時間戳, timestamp2 - timestamp1 < 60,則斷定爲一次合法請求,而後保存 nonce
  5. 服務端只保存60秒內的 nonce,定時將集合內過時的 nonce 刪除

該集合不該該直接操做文件或者數據庫,不然服務端 IO 太多,形成性能瓶頸。能夠是 mmap 或者其餘內存到文件的讀寫機制。根據場景能夠選擇樂觀鎖、悲觀鎖。

其中有一個 timestamp 的問題,服務器會將請求參數中的 timestamp 判斷差值,其中一個致命的缺點是服務器的時間和客戶端的時間是存在時間差的,固然你也能夠經過校驗時間戳解決此問題。時間同步請繼續看下面部分。

4、 計算機網絡時間同步技術原理

客戶端和服務端的時間同步在不少場景下很是重要,舉幾個例子,這些場景都是常常發生的。

  • 一個商品秒殺系統。用戶打開頁面,瀏覽各個類目的商品,商品列表界面右側和詳情頁都有倒計時秒殺功能。用戶在詳情頁加購、下單、結算。發現彈出提示「商品庫存不足,請購買同類其餘品牌商品」
  • 一個答題系統,題目是該公司核心競爭力。因此有心的程序員爲接口設計了「防重放」功能。可是前端小哥不給力,接口帶過去的 timestamp 與服務器不在一個時區,差好幾秒。別有用心的競品公司的爬蟲工程師發現了該漏洞,爬取了題目數據。

因此該現象在計算機領域有很是廣泛,有解決方案。

  1. 若是精度要求不高的狀況下:先請求服務器上的時間 ServerTime,而後記錄下來,同時記錄當前的時間 LocalTime1;須要獲取當前的時間時,用最新的當前時間 (LocalTime2 - LocalTime1 + ServerTime)

    拿 iOS 端舉例:

    • App 啓動後經過接口獲取服務器時間 ServerTime,保存本地。並同時記錄當前時間 LocalTime1
    • 須要使用服務器時間時,先拿到當前時間 LocalTime2 - LocalTime1 + ServerTime
    • 若獲取服務器時間接口失敗,則從緩存中拿到以前同步的結果(初始的時間在 App 打包階段內置了)
    • 使用 NSSystemClockDidChangeNotification 監測系統時間發生改變,若變化則從新獲取接口,進行時同步
  2. 若是須要精度更高,好比 100納秒的狀況,則須要使用 NTP(Network Time Protocol)網絡時間協議、PTP (Precision Time Protocol)精確時間同步協議了。

NTP、PTP 不在本文的範疇,感興趣的能夠查看這篇文章

相關文章
相關標籤/搜索