こんにちは。哥倫比亞大學博士班、研究系統安全的 Koukyosyumei。

這幾天,我看到與資安事件相關的新聞變多了。看到這類新聞時,很多人或許都會想:「我的 Web 服務沒問題吧?」

談到對 Web 應用程式的攻擊,腦中可能會浮現技術高超的駭客,使用複雜程式入侵,或運用社交工程的畫面。不過在實際的資安檢測與漏洞賞金中,往往也會從更簡單的地方開始調查。

例如:

  • 在 URL 末尾加上 .env 或 .git/config
  • 從 GitHub 公開儲存庫尋找 API 金鑰
  • 在搜尋欄輸入特殊字串
  • 把 API 的使用者 ID 改成別人的
  • 在短時間內重複做同一個操作

乍看之下都是很單純的操作,但光是這些,就有可能發現重大漏洞。

當然,Web 應用程式的漏洞不只這些。XSS、SQL Injection、SSRF、授權不足、商業邏輯問題等,都是攻擊者會關注的重點。

本文將從「攻擊者會檢查 Web 應用程式的哪些地方」這個角度出發,介紹一份初學者也能輕鬆在自己的服務上實踐的資安檢查清單。

我盡量整理成即使沒有太多專業知識也能執行的形式,並附上具體的確認方式與發現問題時的處理方法。

另外,本文介紹的主要是用來找出 Web 應用程式本身漏洞的方法。像 MFA、備份、日誌監控等營運面資安措施也很重要,但這次不會涵蓋。

注意:以下測試僅限於你自己擁有的 Web 服務,或已明確取得測試許可的環境。請盡可能使用本機環境或 staging 環境,並搭配測試帳號與測試資料。

1. 先確認外部看得到哪些資訊?

攻擊者在檢視 Web 應用程式時,最先做的事情之一就是偵察與資訊蒐集(Reconnaissance)。他們會調查有哪些 API、使用了哪些框架、有沒有洩漏內部資訊等。

1.1 設定檔或備份檔沒有公開嗎

例如,Web 伺服器設定錯誤時,開發時使用的設定檔可能會直接被公開。請在自己的 Web 服務中確認以下 URL:

https://example.com/.env
https://example.com/.git/config
https://example.com/backup.zip
https://example.com/.env.bak

.env 可能包含資料庫密碼或 API 金鑰,.git 可能包含原始碼歷史。

不過,光是回傳 HTTP 200,並不代表檔案真的被公開。有些 SPA 會對不存在的 URL 回傳同一份 HTML,因此也要確認回應內容。

1.2 GitHub 公開儲存庫中沒有機密資訊嗎

如果你有把程式碼公開在 GitHub,也要注意。很好用的工具是 OSS 的 Gitleaks,它可以從 Git 的 commit 歷史中偵測 API 金鑰、密碼等機密資訊。

在 macOS 上可以這樣安裝:

brew install gitleaks

把自己的儲存庫 clone 下來後,執行以下指令:

gitleaks git . --redact

不只目前的程式碼,連過去的 commit 也都會納入檢查。若偵測到機密資訊,不只是從 Git 中刪除字串而已,還要讓可能外洩的金鑰失效並重新發行。

1.3 API 與 JavaScript 沒有洩漏內部資訊嗎

接著,打開 Chrome 的開發者工具,查看 Network 與 Sources 分頁。你可以觀察 Web 服務呼叫了哪些 API,以及傳送了哪些 JavaScript。

例如,可能會發現:

  • Swagger 或 OpenAPI 文件
  • 管理員用 API 端點
  • source map(.js.map)
  • staging 環境網址
  • 開發時留下的註解或除錯資訊

這些內容被公開,並不代表一定立刻形成漏洞,但仍值得確認是否含有不該公開的資訊。

檢查清單

  • .env、.git、備份等沒有被意外公開
  • 已用 Gitleaks 掃描 GitHub 公開儲存庫
  • JavaScript 或 HTML 中沒有機密資訊
  • 沒有透過 Swagger/OpenAPI 公開內部專用資訊
  • 正式環境沒有啟用不必要的除錯功能

2. 能否濫用使用者輸入?

Web 應用程式中有很多接收外部資料的地方,例如搜尋欄、登入表單、留言、檔案上傳等。攻擊者會試著透過這些輸入,讓原本應該只是資料的字串,被當成程式或指令來解讀。

2.1 XSS:輸入的字串會不會被當成 JavaScript 執行?

這類攻擊中最有名的之一就是 XSS(Cross-Site Scripting),也就是讓 Web 頁面執行不該執行的腳本。

例如,假設有一個可以發表留言的 Web 服務。正常情況下,輸入的字串應該會以文字顯示。但如果 HTML 的處理方式不當,輸入內容可能會被當成 HTML 解析。

先在自己的測試環境的搜尋欄或留言欄輸入以下字串:

<b>security-test</b>

在輸入的位置或其他頁面上,這段文字會原樣顯示嗎?還是會意外被當成粗體 HTML?

如果被當成 HTML 解析,就有可能進一步導致 XSS,需要再深入確認。不過,像 Markdown 編輯器這類功能,本來就可能有意地渲染 HTML。HTML 被解析本身,不一定就代表 XSS。更精確地說,重點是:使用者可控制的字串,是否會導致非預期的 JavaScript 執行。

檢查清單

  • 搜尋欄或留言欄中的 HTML 特殊字元有被安全處理
  • 儲存的輸入內容在其他頁面顯示時,不會執行危險腳本
  • URL 查詢參數能安全顯示
  • Markdown 或富文字中的 HTML 有正確過濾
  • 沒有把不可信字串直接丟進 JavaScript 的 innerHTML 等位置

基本對策是,依照輸出位置的上下文,做適當的 escape 或 sanitize,例如 HTML、JavaScript、URL 各自都要採用對應的處理方式。

參考:OWASP Cross Site Scripting Prevention Cheat Sheet

2.2 SQL Injection:輸入會不會改變資料庫查詢?

SQL Injection 是指使用者輸入影響了 SQL 語句結構的漏洞。

例如,假設有一個搜尋使用者名稱的功能:

SELECT * FROM users WHERE name = 'alice';

如果這段 SQL 是用字串串接組出來的,會怎樣呢?

query = "SELECT * FROM users WHERE name = '" + name + "'"

就可能依照 name 的內容產生非預期的 SQL。

在你的服務中,可以先在搜尋欄或篩選條件輸入單引號(')等特殊字元,確認是否會出現異常錯誤。

不過,沒有錯誤並不代表不存在 SQL Injection。更重要的是確認實作是否使用參數化查詢。例如在 Python 裡,可以這樣寫:

cursor.execute(
    "SELECT * FROM users WHERE name = ?",
    (name,)
)

透過分離 SQL 結構與輸入值,可以避免使用者輸入被當成 SQL 語法解析。

檢查清單

  • 搜尋、登入、篩選功能沒有用字串串接組 SQL
  • 有使用參數化查詢
  • 無法參數化的識別字,例如排序欄位名稱,已用允許清單限制
  • 不正確的輸入不會把 SQL 錯誤或 stack trace 顯示給外部
  • 資料庫連線帳號沒有被賦予多餘權限

NoSQL 資料庫也可能有把外部輸入當成查詢運算子解讀的問題,因此同樣要注意。

參考:OWASP SQL Injection Prevention Cheat Sheet

2.3 Command Injection:輸入沒有被傳給 shell 指令嗎?

圖片轉換、PDF 產生、檔案壓縮等功能,常會從後端呼叫外部指令。例如,把檔名用字串串接組成 shell 指令的做法,就可能成為 Command Injection 的原因。

攻擊者會確認,能否透過修改檔名或參數,讓系統執行不該執行的指令。

例如,假設 Web 應用程式在轉換圖片時,會用 Python 執行外部指令:

import os

filename = request.args["filename"]
os.system(f"convert {filename} output.png")

原本可能預期輸入像 image.jpg 這樣的檔名,但如果攻擊者把檔名指定為 image.jpg; touch /tmp/injection.txt,; 可能會被 shell 當作指令分隔符,進而執行無關的 touch 指令。

檢查清單

  • 沒有把外部輸入串接成 shell 指令字串
  • 沒有貿然使用 shell=True
  • 呼叫外部程式時,是以結構化方式傳遞參數
  • 有適當驗證檔名與選項

如果可以,最好不要經過 shell,而是直接使用函式庫 API。

3. 本來不能做的操作,是否被做到了?

Web 應用程式安全中特別重要的,還有存取控制與商業邏輯的驗證。

即使沒有輸入 XSS 或 SQL Injection 那類特殊字串,只要稍微改一下正常的 HTTP request,也可能找到重大問題。

3.1 IDOR:能否取得或修改別人的資料?

例如,登入使用者可以透過以下 API 取得自己的個人資料:

GET /api/users/123

這裡的 123 是自己的使用者 ID。

攻擊者會嘗試把這個 ID 改成別人的,確認是否也能取得資料:

GET /api/users/124

如果能取得其他使用者的非公開資訊,就可能存在 IDOR(Insecure Direct Object Reference)之類的授權缺陷。

實際確認方式

在自己的測試環境中,建立兩個使用者:Alice 和 Bob。

  1. 以 Alice 登入
  2. 確認取得 Alice 資料的 API
  3. 把 request 中的 ID 改成 Bob 的
  4. 確認 Alice 的權限下無法取得 Bob 的非公開資料

更新與刪除 API 也同樣測試一次。

特別是 SaaS 服務中,不能存取其他組織或 tenant 的資料也很重要。

檢查清單

  • 即使指定別人的使用者 ID,也無法取得非公開資料
  • 不能修改或刪除別人的檔案或訂單
  • 不能存取其他組織或 tenant 的資料
  • 一般使用者不能呼叫管理員 API
  • 授權驗證不只在前端做,也有在後端做

3.2 Mass Assignment:會不會接受意料之外的參數?

接著,來看 API 接收的 JSON。例如,使用者個人資料更新 API 可能會收到如下 request:

{
  "display_name": "Alice"
}

如果伺服器端把客戶端傳來的 JSON 直接反映到使用者模型上,會怎樣呢?

{
  "display_name": "Alice",
  "role": "admin"
}

原本不該變更的 role 可能也被寫入。這就是 Mass Assignment 的典型問題。

檢查清單

  • API 明確限制可更新的欄位
  • 一般使用者不能修改 role、is_admin、owner_id 等欄位
  • 不會把客戶端傳來的 JSON 無條件套用到 DB 模型
  • 管理員才能修改的欄位,在伺服器端有授權檢查

實際確認時,可以在測試環境加入意料之外的欄位,確認它是否會寫入資料庫。

3.3 商業邏輯:把正確的 API 組合起來,會不會做出不正當的事?

到目前為止,多半是在談單一 API 的問題。但即使每個 API 單獨看都沒問題,把它們組合起來後,仍可能出現漏洞。

例如考慮電商網站的優惠券流程:

  • 優惠券只能使用一次
  • 付款 API 正常
  • 使用優惠券 API 也正常

但如果處理順序或競態條件有問題,就可能讓同一張優惠券被重複使用。攻擊者會特別注意這種「原本不該發生的操作順序」。

檢查清單

  • 優惠券或點數不能被不正當地重複使用
  • 不能不付款就取得商品或付費功能
  • 不能略過工作流程中的中間步驟
  • 同一操作在短時間內重複執行時,系統仍能維持一致性
  • 不能濫用邀請、推薦獎勵、免費試用等機制

這類 bug 通常不容易被單純的弱點掃描器發現,所以特別值得花時間調查。

4. 能否濫用伺服器背後的東西?

接著要確認的是,攻擊者是否能透過 Web 應用程式存取內部網路或檔案系統等。

4.1 SSRF:能否讓伺服器去存取不該去的 URL?

近年的 Web 服務常見這種功能:使用者輸入 URL,伺服器去存取該 URL。

例如:

  • 產生 URL 預覽
  • 從 URL 下載圖片
  • 測試 Webhook 連線
  • 把外部網頁轉成 PDF

如果這類功能沒有妥善限制 URL,攻擊者可能讓伺服器對不該接觸的目標送出 request。這就是 SSRF(Server-Side Request Forgery)。

例如,假設有個 Web 應用程式會從使用者指定的 URL 下載圖片:

import requests

url = request.args["url"]
response = requests.get(url)

正常預期會輸入像 https://example.com/image.png 這樣的 URL。但如果攻擊者指定 http://127.0.0.1:8080/admin,就可能讀到執行 Web 應用程式的伺服器資訊。

實際測試 SSRF 時,如果你的服務有輸入 URL 的功能,可以準備一台測試用 HTTP 伺服器,確認對該 URL 的存取會如何處理。例如,在本機測試環境中確認不允許的內部目標 URL 是否會被拒絕。

檢查清單

  • 已適當限制內部網路與 loopback 位址的連線
  • 已掌握會取得外部 URL 的功能
  • 也有檢查 redirect 後的目標
  • 已考慮 DNS 解析結果並限制連線目的地
  • 從伺服器對外連線的範圍維持在最小必要程度

參考:OWASP SSRF Prevention Cheat Sheet

4.2 檔案上傳・Path Traversal

檔案上傳與下載功能,也是攻擊者會特別關注的地方。

例如:

GET /download?file=report.pdf

如果這個 API 直接把 request 的 file 參數當成檔案路徑來用,會怎樣呢?

只要稍微設計輸入,就可能存取到原本不公開的檔案。這就是 Path Traversal 的典型問題。

另外,也可能有圖片上傳功能其實接受了任意檔案,甚至把上傳檔案放到伺服器上可執行的位置。

檢查清單

  • 不能透過檔名參照到非預期目錄
  • 已限制檔案上傳允許的格式
  • 不只檢查副檔名,也有正確檢查檔案內容
  • 上傳檔案不會被放到可執行的位置
  • 下載非公開檔案時也會確認授權
  • 有適當限制檔案大小與處理量

避免直接從外部輸入組出檔案路徑,或改用 file ID 來安全管理,會是有效的做法。

4.3 依賴函式庫有已知漏洞嗎?

就算自己寫的程式沒有漏洞,依賴函式庫也可能有問題。先確認目前使用的函式庫是否存在已知漏洞。

Node.js:

npm audit

Python:

pip-audit

Rust:

cargo audit

也可以使用 GitHub Dependabot,持續接收依賴關係漏洞的通知。

檢查清單

  • 已掃描依賴函式庫的已知漏洞
  • 已確認重大漏洞是否會影響自己
  • 沒有使用已停止支援的 runtime 或 framework
  • 已移除不必要的依賴與舊功能
  • 能持續套用安全修補

5. 也要確認現代 Web 應用特有的攻擊

到目前為止介紹的,主要是長期以來已知的漏洞。不過,現代 Web 服務會結合 CDN、OAuth、GraphQL、WebSocket、生成式 AI 等多種技術,這些架構也會帶來特有的攻擊。

5.1 OAuth / SSO 設定不良

如果使用 Google 登入等 OAuth/OIDC,就需要確認認證流程本身是否設計正確。

例如,如果登入完成後的重新導向目的地可以任意指定,或認證回應與原始登入請求沒有正確關聯,就可能引發問題。

檢查清單

  • 嚴格限制 redirect URI
  • 透過 state 等機制正確驗證請求關聯
  • 在 OIDC 中,依流程需求驗證 nonce 等項目
  • 在授權碼流程中正確使用 PKCE
  • 不要只因為電子郵件地址相同,就草率合併不同帳號

5.2 Web Cache Poisoning / Cache Deception

如果有使用 CDN 或 reverse proxy,也要注意快取設定。

Web Cache Poisoning 是指攻擊者影響會被快取的回應,讓其他使用者收到不該看到的內容。

Web Cache Deception 則是把原本不該快取的個人化回應,意外存進共享快取。

檢查清單

  • 含有個人資訊的頁面沒有被存進共享快取
  • 依賴 Cookie 或驗證資訊的回應,其快取策略是正確的
  • CDN 與後端對 URL 或路徑的解讀沒有不一致
  • 已掌握會影響 cache key 的 HTTP header 與參數

在測試環境中,確認使用者 A 的非公開回應不會被回傳給使用者 B。

5.3 GraphQL / WebSocket API 的授權不足

即使不是 REST API,存取控制的驗證也很重要。例如 GraphQL 可以透過單一端點取得很多種類的資料,因此每個欄位與物件都需要適當授權。

WebSocket 也是如此,即使在連線時已認證,也可能沒有對每則訊息或每個操作做權限檢查。

檢查清單

  • GraphQL 的各個操作與欄位都有適當授權
  • 有限制 GraphQL 查詢深度與執行成本
  • WebSocket 不只在連線時驗證,也有在每個操作時驗證
  • 不能訂閱別人的事件或非公開訊息
  • 沒有公開不必要的除錯資訊或 schema

總結:用攻擊者視角檢查自己的 Web 應用程式

到這裡,我們介紹了在檢視 Web 應用程式時,最常被注意到的幾個重點。最後整理成檢查清單。

先確認的 10 項

  • .env、.git、備份等沒有公開
  • 已用 Gitleaks 檢查 GitHub 公開儲存庫
  • 沒有會導致 XSS 的危險 HTML / JavaScript 處理
  • 不會發生 SQL Injection 或 Command Injection
  • 不能取得或修改別人的資料
  • 對 API 傳入意料之外的參數時,不會發生權限提升
  • 不能不正當地重複使用優惠券或付款流程
  • 不會發生 SSRF 或 Path Traversal
  • 已確認依賴函式庫的已知漏洞
  • 已確認 OAuth、快取、GraphQL、WebSocket,以及所使用功能的特定風險

當然,確認這些內容不代表就能保證 Web 應用程式一定安全。不過,理解攻擊者會如何檢查 Web 應用程式,並且自己也用相同視角來檢查,正是提升資安的第一步。

另外,測試不應只做一次,而是要隨著新功能加入與程式碼變更持續進行。

再進一步:使用 AI 的自動 Red Teaming 與形式驗證

上面介紹的檢查中,有些可以比較簡單地手動確認。不過,當 Web 應用程式變得更複雜時,要手動檢查所有 API、畫面與使用者權限組合會非常困難,也需要專業知識。

這時,安全測試自動化就很有幫助。例如,OWASP ZAP 與 Burp Suite 等工具,都是業界常用的方案。

另外,近年也有讓 AI agent 操作 Web 應用程式,協助發現漏洞的方法。

h5i:使用 AI agent 測試 Web 應用程式

最後,容我介紹一下我正在開發的 OSS h5i。h5i 是一個給 AI agent 使用的工具,用來提升 Web 應用程式的安全性。

它可以讓 AI agent 操作瀏覽器,也可以記錄、修改並重新送出 HTTP request。例如,可把以下檢查交給 AI agent 來做:

  • 探索 Web 應用程式中的 API
  • 修改 HTTP request 來檢查授權缺陷
  • 檢查輸入表單或 API 的異常行為
  • 記錄發現的問題與重現步驟

h5i 本身是免費的 OSS,除非你使用外部 AI 模型,否則不會產生軟體使用費。如果有興趣,歡迎試試看。只要安裝 h5i 的 binary,並請 Claude Code 或 Codex 等工具下達「使用 h5i 監査這個 Web 應用程式」這類指令,就能執行較完整的攻擊測試。你也可以透過 h5i ui 這個指令查看直觀的儀表板。

image.png

不只找出漏洞,也要證明沒有漏洞

h5i 不只用來找漏洞,也提供一套框架,讓你在開發 Web 應用程式時,同時證明原本就沒有某些漏洞。

一般的資安測試,是透過實際送出 request 或修改輸入,來找出漏洞存在的證據。

相對地,形式驗證的目標是,以數學方式證明「某一類漏洞不會發生」。例如,對於多組織共用的 Web 應用程式,可以證明「組織 A 的使用者無法存取組織 B 的非公開資料」這類性質。

h5i 正在開發一套機制,結合 Rust 的 Web 應用程式框架與名為 Lean 4 的定理證明助理,來驗證這類性質。

當然,證明也有前提條件與適用範圍,並不代表整個 Web 應用程式會無條件變安全。即便如此,我仍認為,把「攻擊來找漏洞」與「證明沒有漏洞」結合起來,能幫助打造更可靠的 Web 服務。


參考資料


原文出處:https://qiita.com/Koukyosyumei/items/8aaa44ff15a3b404fd8b


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝49   💬2  
706
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
📢 贊助商廣告 · 我要刊登