SQL Injection 防護
攻擊範例
# ❌ 危險寫法 - SQL Injection
user_input = "' OR '1'='1"
query = f"SELECT * FROM users WHERE email = '{user_input}'"
# 變成: SELECT * FROM users WHERE email = '' OR '1'='1'
# 回傳所有使用者!!!
# ✅ 安全寫法 - 參數化查詢
import psycopg2
conn = psycopg2.connect("dbname=test")
cur = conn.cursor()
cur.execute("SELECT * FROM users WHERE email = %s", (user_input,))
ORM 防護(Supabase)
// ✅ Supabase 安全查詢
const { data } = await supabase
.from('users')
.select('*')
.eq('email', userInput) // 自動參數化
Vibe Prompt
「幫我檢查這段程式碼的 SQL Injection 風險,並改成安全的參數化查詢。」
# 請修復這段程式碼
username = request.GET['username']
query = f"SELECT * FROM users WHERE username = '{username}'"
關鍵要點
- ✅ OWASP Top 10 = Web 應用安全最具權威的風險列表
- ✅ SQL Injection:永遠使用參數化查詢,不要串接字串
- ✅ XSS:對使用者輸入進行轉義(Escape),使用 CSP Header
- ✅ CSRF:使用 SameSite Cookie + CSRF Token 雙重保護
- ✅ 安全是設計階段就要考慮的,不是上線前才補
OWASP Top 10 (2021)
| 排名 | 漏洞 | 說明 | |:----:|------|------| | A01 | 權限控制失效 | IDOR、越權 | | A02 | 加密機制失效 | 未加密敏感資料 | | A03 | 注入攻擊 | SQL、NoSQL、Command Injection | | A04 | 不安全設計 | 安全未在設計階段考慮 | | A05 | 安全配置錯誤 | 預設密碼、未關閉除錯模式 | | A06 | 脆弱元件 | 使用有已知漏洞的套件版本 | | A07 | 認證與身分管理失效 | 弱密碼、Session 固定 | | A08 | 資料完整性失效 | 不安全的反序列化 | | A09 | 日誌與監控不足 | 無法偵測攻擊 | | A10 | SSRF | 伺服器端請求偽造 |
各語言安全查詢範例
# Python - psycopg2 (PostgreSQL)
cur.execute("SELECT * FROM users WHERE email = %s", (email,))
```javascript
// Node.js - pg
await client.query("SELECT * FROM users WHERE email = $1", [email])
```go
// Go - database/sql
db.Query("SELECT * FROM users WHERE email = $1", email)
```java
// Java - JDBC
PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE email = ?");
ps.setString(1, email);
進階攻擊:Second-Order SQL Injection
即使使用了參數化查詢,如果應用程式從資料庫讀取資料後又將其串接到新查詢中,仍可能觸發攻擊:
1. 使用者註冊時使用者名稱為 "admin'--"
2. 資料庫安全地儲存了這個使用者名稱
3. 管理員在後台執行 "SELECT * FROM users WHERE name = '" + user.name + "'"
4. 觸發注入!
解決方案:不僅在寫入時使用參數化查詢,在讀取後的任何二次查詢也必須使用參數化。
ORM 的安全陷阱
ORM(如 Prisma、TypeORM、Sequelize)預設是安全的,但以下情況可能繞過保護:
// ❌ 不安全:使用原始查詢
prisma.$queryRawUnsafe(`SELECT * FROM users WHERE id = ${id}`)
// ✅ 安全:使用參數化
prisma.$queryRaw`SELECT * FROM users WHERE id = ${id}`
SQL Injection:經典不滅的漏洞
SQL Injection 是 Web 安全中最古老但也最危險的漏洞之一。它是 OWASP Top 10 的常客,每年仍然造成大量資料外洩事件。
為什麼 Parameterized Query 可以防 SQL Injection?
-- ❌ 錯誤:字串拼接
-- 輸入:' OR '1'='1
SELECT * FROM users WHERE email = '' OR '1'='1'
-- 回傳所有使用者!登入成功!
-- ✅ 正確:參數化查詢
-- 輸入:' OR '1'='1
SELECT * FROM users WHERE email = ?
-- 資料庫把整個 ' OR '1'='1 當成字串值
-- 找不到這個 email,登入失敗
參數化查詢(Prepared Statement)把 SQL 語法和使用者輸入分開——輸入永遠被當成資料,不會變成語法的一部分。
下一章預告:XSS 與 CSP
SQL Injection 攻擊的是資料庫。下一章的 XSS 攻擊的是瀏覽器——讓受害者執行惡意 JavaScript。