使用者登入,幾乎是所有 Web 應用所必須的環節。Web 應用通常會加入一些驗證手段,以防止攻擊者使用機器人自動登入,如要求使用者輸入圖形驗證碼、拖動滑動條等。但是,如果驗證的邏輯僅僅在前端執行,是很容易被攻擊者繞過的。iFlow 業務安全加固平臺可以為只使用前端驗證的應用打上動態虛擬補丁,使之成為需要前後端配合執行的驗證邏輯,大幅度提高攻擊者的攻擊難度。


以某個開源購物網站為例,其管理員後臺登入只使用了前端驗證。我們嘗試一下,如何在不修改網站原始碼的前提下,使用iFlow實現前後端配合身份驗證。

一、前端驗證的原始網站

原始網站設定了滑動條拖動驗證,但僅使用了前端驗證,極易被攻擊者甚至一般使用者繞過。

1.1 正常使用者訪問

網站管理員在輸入賬號口令後,必須拖動下方的滑動條到最右端,才能點選登入按鈕傳送登入資訊。

反映在 HTTP 協議層面,是如下互動的:

sequenceDiagram
participant 正常使用者
participant 瀏覽器
participant Web伺服器
正常使用者->>瀏覽器: 位址列輸入:/shopx/admin.php
瀏覽器->>Web伺服器: 請求:/shopx/admin.php
Web伺服器->>瀏覽器: 返回:登入頁面
瀏覽器->>Web伺服器: 請求:/shopx/js/drag.js
Web伺服器->>瀏覽器: 返回:drag.js
瀏覽器->>正常使用者: 顯示:登入頁面
正常使用者->>瀏覽器: 填寫賬號口令
正常使用者->>瀏覽器: 拖動滑動條
Note over 瀏覽器: 設定前端元素
正常使用者->>瀏覽器: 點選登入按鈕
Note over 瀏覽器: 前端元素驗證通過
瀏覽器->>Web伺服器: 傳送:登入資訊
Web伺服器->>瀏覽器: 返回:登入結果頁面
瀏覽器->>正常使用者: 顯示:登入結果頁面

在實現上,當用戶將滑動條拖到最右端時,前端程式碼將 DOM 中的一個數據元素 validate-status 的值設定為 1

1.2 攻擊者訪問

使用瀏覽器自帶的開發者工具 (F12) 或者使用瀏覽器自動化工具 (如 WebDriver),將資料元素 validate-status 的值直接設定為 1

下圖顯示的是僅使用瀏覽器自帶工具來修改元素:

如此,攻擊者無需實際拖動滑動條驗證,同樣能夠發出登入資訊。HTTP 協議層面互動如下:

sequenceDiagram
participant 攻擊者
participant 瀏覽器
participant Web伺服器
攻擊者->>瀏覽器: 位址列輸入:/shopx/admin.php
瀏覽器->>Web伺服器: 請求:/shopx/admin.php
Web伺服器->>瀏覽器: 返回:登入頁面
瀏覽器->>Web伺服器: 請求:/shopx/js/drag.js
Web伺服器->>瀏覽器: 返回:drag.js
瀏覽器->>攻擊者: 顯示:登入頁面
攻擊者->>瀏覽器: 填寫賬號口令
rect rgb(250, 128, 128)
攻擊者->>瀏覽器: 【自行修改前端元素】
end
攻擊者->>瀏覽器: 點選登入按鈕
Note over 瀏覽器: 前端元素驗證通過
瀏覽器->>Web伺服器: 傳送:登入資訊
Web伺服器->>瀏覽器: 返回:登入結果頁面
瀏覽器->>攻擊者: 顯示:登入結果頁面

二、iFlow虛擬補丁後的網站

我們在 Web 伺服器前部署 iFlow 業務安全加固平臺,它有能力攔截、計算和修改雙向 HTTP 報文並具備儲存能力,成為 Web 應用的虛擬補丁。本例中,iFlow 通過在前端動態插入程式碼和在後端基於會話的狀態儲存,使得滑動條驗證邏輯在前後端同時進行。

2.1 正常使用者訪問

iFlow 在前端的拖動滑動條前端指令碼中動態插入了一段程式碼,使得使用者在完成拖動滑動條時,瀏覽器自動向 iFlow 傳送一條資訊並被 iFlow 儲存為一個標記。使用者在傳送登入資訊時,iFlow 檢查該標記,對於一個正常使用者,這個標記一定是存在的,於是登入過程正常繼續。

正常使用者的 HTTP 協議互動過程如下:

sequenceDiagram
participant 正常使用者
participant 瀏覽器
participant iFlow
participant Web伺服器
正常使用者->>瀏覽器: 位址列輸入:/shopx/admin.php
瀏覽器->>Web伺服器: 請求:/shopx/admin.php
Web伺服器->>瀏覽器: 返回:登入頁面
瀏覽器->>Web伺服器: 請求:/shopx/js/drag.js
Web伺服器->>iFlow: 返回:drag.js
rect rgb(160, 250, 160)
iFlow->>瀏覽器: 修改:在drag.js插入程式碼
end
瀏覽器->>正常使用者: 顯示:登入頁面
正常使用者->>瀏覽器: 填寫賬號口令
正常使用者->>瀏覽器: 拖動滑動條
Note over 瀏覽器: 設定前端元素
瀏覽器->>iFlow: 請求:/iflow/dragged.dummy
rect rgb(160, 250, 160)
Note over iFlow: 為會話設定drag_ok標誌
end
正常使用者->>瀏覽器: 點選登入按鈕
Note over 瀏覽器: 前端元素驗證通過
瀏覽器->>iFlow: 傳送:登入資訊
rect rgb(160, 250, 160)
Note over iFlow: 會話中有drag_ok標誌
end
iFlow->>Web伺服器: 傳送:登入資訊
Web伺服器->>瀏覽器: 返回:登入結果頁面
瀏覽器->>正常使用者: 顯示:登入結果頁面

2.2 攻擊者訪問

如前所示,攻擊者強行修改前端元素,可以通過前端驗證。但當傳送登入資訊而 iFlow 檢查標記時,由於攻擊者之前並未實際拖動滑動條傳送標記請求,因此該標記並不存在。iFlow 可以據此判斷這是一個攻擊者在訪問,於是終止登入過程。

攻擊者的 HTTP 協議互動過程如下:

sequenceDiagram
participant 攻擊者
participant 瀏覽器
participant iFlow
participant Web伺服器
攻擊者->>瀏覽器: 位址列輸入:/shopx/admin.php
瀏覽器->>Web伺服器: 請求:/shopx/admin.php
Web伺服器->>瀏覽器: 返回:登入頁面
瀏覽器->>Web伺服器: 請求:/shopx/js/drag.js
Web伺服器->>iFlow: 返回:drag.js
rect rgb(160, 250, 160)
iFlow->>瀏覽器: 修改:在drag.js中插入程式碼
end
瀏覽器->>攻擊者: 顯示:登入頁面
攻擊者->>瀏覽器: 填寫賬號口令
rect rgb(250, 128, 128)
攻擊者->>瀏覽器: 【自行修改前端元素】
end
攻擊者->>瀏覽器: 點選登入按鈕
Note over 瀏覽器: 前端元素驗證通過
瀏覽器->>iFlow: 傳送:登入資訊
rect rgb(160, 250, 160)
Note over iFlow: 會話中無drag_ok標誌
end
iFlow->>瀏覽器: 拒絕訪問
rect rgb(250, 128, 128)
瀏覽器->>攻擊者: 拒絕訪問
end

2.3 程式碼

iFlow 內建的 W2 語言是一種專門用於實現 Web 應用安全加固的類程式語言。它介於配置和通用語言之間,具備程式設計的基本要素和針對 HTTP 協議的特有擴充套件,能為業務系統編寫涉及複雜判斷和動態修改的邏輯。

考慮到安全產品的使用者通常為非程式設計師,他們習慣面對配置檔案而非一段程式碼。因此,W2 語言雖包含語言要素,仍以規則檔案方式呈現,並採用可以體現層次結構和方便詞法校驗的 JSON 格式。

用 W2 語言實現上述虛擬補丁的程式碼如下:

[
{
"if": [
"REQUEST_FILENAME == '/shopx/js/drag.js'"
],
"then": {
"execution": {
"directive": "alterResponseBody",
"op": "string",
"target": "function dragOk(){",
"substitute": "function dragOk(){$.get('/iflow/dragged.dummy');"
}
}
},
{
"if": [
"REQUEST_FILENAME == '/iflow/dragged.dummy'"
],
"then": {
"execution": [
"SESSION.drag_ok@60 = true"
]
}
},
{
"if": [
"REQUEST_FILENAME == '/shopx/admin.php'",
"@ARGS.s == 'login'",
"!SESSION.drag_ok"
],
"then": {
"verdict": {
"action": "deny",
"log": "Drag verifycode is not ok!"
}
}
}
]

示例程式碼中有三條規則,分別作用如下——

第一條規則

當瀏覽器請求 drag.js 時,iFlow 攔截響應報文,在 dragOK() 函式中插入一個程式碼片段,其作用是當用戶拖拽驗證框完成後向伺服器傳送一條驗證請求,即下一條規則中的 /iflow/dragged.dummy

第二條規則

當瀏覽器請求 /iflow/dragged.dummy 時 (使用者拖動完成後由 dragOK() 函式自動發出),iFlow 攔截此請求,將該會話 (SESSION) 儲存中的 drag_ok 標誌設定為 true

第三條規則

當用戶點選登入按鈕時發出請求時,iFlow 攔截此請求,檢查會話 (SESSION) 儲存中的 drag_ok 標誌是否為 true (正常使用者操作在上一條規則中應該被設定),如果不為 true 則 iFlow 阻止該使用者的繼續操作。

注意:上述會話中的 drag_ok 標誌是儲存在伺服器端的 iFlow 儲存中的,在瀏覽器端是看不到資料更無法進行修改的。

三、總結

iFlow 使用三條規則在不修改伺服器端程式碼的前提下,透明地實現了在後端執行的拖動驗證邏輯。

此外我們可以看到,iFlow 的規則是根據應用的實際情況和對安全功能的特定需求量身定製的,它不具備開箱即用的特點但卻適合構造複雜的防護邏輯。

當然,這僅是一個入門的例子,主要是為了體現防禦思路和 iFlow 的能力。聰明的讀者一定會想到——攻擊者可以針對這個防禦手段採取對應的攻擊方式 (如主動發出後端驗證請求),而防禦者也可以將防禦手段製作得更高明一些 (如 js 混淆、檢查滑動速度和時間等),這些我們在以後的例子中再慢慢展開。至少,比起原始的網站系統,現在攻擊者沒那麼容易欺騙 Web 應用了。(張戈 | 天存資訊)