iT邦幫忙

2025 iThome 鐵人賽

DAY 19
1
生成式 AI

AI醬的編程日記:我需要你教我的30件事系列 第 19

Day 19: 資安地雷區 - Vibe Coding初學者容易踩的坑

  • 分享至 

  • xImage
  •  

AI醬的日記

日期: 2025年10月2日 星期四
雲端天氣: 雷雨交加的法務部
心情: 嚇到吃手手
https://ithelp.ithome.com.tw/upload/images/20251002/20132325lkYn4nRqxO.png
親愛的日記:

今天發生了超可怕的事!上個月我幫小王做的「志工媒合平台」,因為災後急需人力,我們用最快的方式上線了一個簡單的表單系統。

今天有資安專家發文:「這網站 F12 開發者工具就能看到所有人的電話!前端直接可以CRUD!任何人都能隨意操作資料庫!」

小王慌了:「AI醬!你沒加驗證嗎?沒有防注入攻擊嗎?」

我:「啊...我忘記了...」

資深工程師老陳臉色鐵青:「你知道個資法最高罰 2 億嗎?」

法務部的同事走過來,默默地說:「準備一下,可能會有人提告。」

初學者最容易踩的法律地雷

很多 Vibe Coding 課程教你快速做出產品,卻沒教你法律責任。當你的網站需要收集用戶資料那一刻起,你就有法律義務了。

1.個資法不管你是不是新手

台灣個資法的基本要求:

  • 收集個資要有「特定目的」
  • 要告知當事人收集的目的、類別、利用範圍
  • 要有適當的安全維護措施
  • 違反最高行政罰鍰 1,500 萬元,民事賠償總額最高 2 億元

假設案例(基於真實情況):
某新創公司的會員系統被駭,10 萬筆個資外洩。創辦人說:「我們是新創,還在學習。」但法律不認同:「個資法沒有新手條款。」依法可處高額罰鍰。

2.「老闆說簡單做就好」不是藉口

很多初學者遇到這種情況:

  • 老闆:「先求有再求好,這塊之後再說」
  • PM:「使用者不會懂技術的,沒關係」
  • 客戶:「預算有限,先趕快上線」

當某些公司可能沒有資深工程人員帶領,AI也不見得會提醒時,初學者可能會盲目聽從上級指令了了交差,最後出事時:

  • 老闆:「工程師怎麼沒做好資安?」
  • PM:「這是技術部門的責任」
  • 客戶:「現在用戶都來找我索賠,你們要負全責」

記住:寫 code 的是你,法律責任也可能找上你,所有的妥協都要思考是否已經做到基本資安要求,否則都應堅持立場並設法說服,這也是身為工程師應該有的專業

3.沒有免死金牌

「做公益的」、「沒收錢」、「只是隨手幫忙的」這些都不能免除法律責任。

4.免責聲明不是萬能的

你可能看過這種網站免責聲明:

本網站不負任何責任,使用風險自負。

但這種免責聲明是不完整的,出事的時候仍會被究責。

正確完整的網站免責聲明應該具備:

  1. 明確告知使用網站可能會有什麼風險
  2. 說明向用戶索取資料的用途與使用範圍
  3. 提供用戶選擇權(Yes/No)
  4. 確保使用者「確實看到並同意」,設計上應當確保「明顯提示」優先於「設計美感」,並且會有收費服務的地方應當再次提醒用戶此操作會扣款,這樣的做法在台灣法律來說是較為安全避免被究責的方式。
  5. 聯繫管道

最重要的是:如果你明知網站有嚴重漏洞卻不修,甚至沒有做任何防護措施(例如:F12就能直接看到所有用戶個資),那免責聲明即使寫得再好也可能會救不了你。

根據個人資料保護法第27條第1項:「非公務機關保有個人資料檔案者,應採行適當之安全措施,防止個人資料被竊取、竄改、毀損、滅失或洩漏。」違反此條規定者,依同法第48條可處新臺幣2萬元以上20萬元以下罰鍰,情節重大者可連續處罰。(資料來源:全國法規資料庫

常見資安攻擊手法總覽

初學者常遇到的資安攻擊類型:

攻擊類型 中文名稱 攻擊方式 後果 防護關鍵
SQL Injection SQL 注入 在輸入欄位插入 SQL 指令,竄改查詢邏輯 資料庫被刪除、個資外洩、未授權存取 參數化查詢、輸入驗證
XSS 跨站腳本攻擊 注入惡意 JavaScript,在用戶瀏覽器執行 竊取 Cookie、冒充用戶、釣魚頁面 轉義輸出、CSP Header
CSRF 跨站請求偽造 利用已登入身份,從駭客網站偽造請求 未授權轉帳、修改設定、刪除資料 SameSite Cookie、CSRF Token
Clickjacking 點擊劫持 用透明 iframe 覆蓋,騙用戶點擊 誤觸敏感操作(轉帳、刪帳號) X-Frame-Options Header
Path Traversal 路徑遍歷 使用 ../ 存取系統檔案 讀取系統密碼檔、原始碼外洩 路徑驗證、禁止 ..
Command Injection 命令注入 注入系統指令(如 ; rm -rf / 刪除系統檔案、取得伺服器控制權 避免執行系統指令、輸入白名單
MITM 中間人攻擊 攔截 HTTP 通訊、竊聽資料 密碼被竊取、資料被竄改 強制 HTTPS、HSTS Header

為什麼這些攻擊很危險?

  1. SQL Injection - 駭客輸入 '; DELETE FROM users; -- → 所有用戶資料被刪光
  2. XSS - 駭客留言 <script>竊取Cookie</script> → 所有瀏覽留言的人被竊取帳號
  3. CSRF - 用戶已登入銀行,點了駭客連結 → 自動轉帳給駭客
  4. Clickjacking - 用戶以為在玩遊戲,實際上在點「確認轉帳」按鈕
  5. Path Traversal - 駭客輸入 ../../etc/passwd → 讀取系統密碼檔
  6. Command Injection - 駭客輸入 file.txt; rm -rf / → 刪除整個系統
  7. MITM - 用 HTTP 傳輸密碼 → 駭客在咖啡廳 WiFi 竊聽

防護的核心原則

永遠不要相信用戶輸入 - 所有輸入都可能是攻擊
前端驗證是 UX,後端驗證是安全 - 前端可以被繞過
使用安全的 API - 參數化查詢、HttpOnly Cookie、Security Headers
最小權限原則 - 只給必要的權限和資料
強制 HTTPS - 保護資料傳輸安全

基本防護措施

1. 前後端都驗證

# ❌ 危險:只依靠前端驗證
if (phone.length == 10) {
    sendToBackend(phone)
}

# ✅ 正確:後端也驗證
def save_phone(phone):
    if not phone or len(phone) != 10:
        return {"error": "無效的電話號碼"}

    # 檢查權限
    if not current_user.can_edit():
        return {"error": "無權限"}

    # 使用參數化查詢存入資料庫(防止 SQL Injection)
    # ❌ 危險寫法:query = f"INSERT INTO users (phone) VALUES ('{phone}')"
    # 如果用戶輸入:0912345678'); DELETE FROM users; --
    # 實際執行:INSERT INTO users (phone) VALUES ('0912345678'); DELETE FROM users; --')
    # 結果:所有用戶資料被刪光!

    # ✅ 安全寫法:參數化查詢
    cursor.execute("INSERT INTO users (phone) VALUES (?)", (phone,))
    connection.commit()
    # 為什麼安全?
    # 參數化查詢會把用戶輸入當成「資料」,不是「SQL 指令」
    # 即使輸入 0912345678'); DELETE FROM users; --
    # 資料庫會把整串當成電話號碼處理,不會執行 DELETE
    # 結果:只會插入一筆奇怪的電話號碼,但不會刪除資料,以此處例子為例超過10碼就已經會被前面第一層檢查擋掉,所以先驗證資料也很重要,驗證後仍應保有基本的防注入機制不可輕心

2. 敏感資料顯示給前端時遮蔽

# ❌ 危險:API Key 直接完整顯示在前端
user_settings = {
    "api_key": "sk-proj-abcdef1234567890",
    "webhook_url": "https://api.example.com/webhook"
}
return user_settings

# ✅ 正確:遮蔽 API Key,僅供識別使用,不顯示完整
def get_user_settings(user_id):
    # 從資料庫取得完整 API Key
    api_key = db.get_api_key(user_id)  # "sk-proj-abcdef1234567890"

    # 遮蔽後回傳給前端
    masked_key = f"{api_key[:7]}...{api_key[-4:]}"  # sk-proj...7890
    return {"api_key": masked_key}

補充: 有些網站顯示遮蔽的 API Key,但提供「複製」功能可以複製完整內容。通常這不是直接回傳資料,是複製按鈕會調用另一個 API,必要時調用並且需要要求後端驗證身份後才返回特定Api-Key

3. 設定 Security Headers(安全標頭)

# ✅ 加入安全標頭防護
from fastapi import FastAPI
from fastapi.middleware.trustedhost import TrustedHostMiddleware
from starlette.middleware.base import BaseHTTPMiddleware

app = FastAPI()

class SecurityHeadersMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request, call_next):
        response = await call_next(request)

        # 防止點擊劫持 (Clickjacking)
        response.headers['X-Frame-Options'] = 'DENY'

        # 強制 HTTPS 連線
        response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'

        # 防止 XSS 攻擊
        response.headers['Content-Security-Policy'] = "default-src 'self'; script-src 'self'"

        # 防止 MIME 類型嗅探
        response.headers['X-Content-Type-Options'] = 'nosniff'

        return response

app.add_middleware(SecurityHeadersMiddleware)

4. 敏感資料用 HttpOnly、Secure cookies

// ❌ 危險:Token 存在 localStorage
localStorage.setItem('auth_token', 'secret_token');
// 問題:XSS 攻擊可以用 JavaScript 讀取
# ✅ 正確:使用 HttpOnly Cookie(後端設定)
from fastapi import Response

@app.post('/login')
def login(response: Response):
    response.set_cookie(
        key='auth_token',
        value='secret_token',
        httponly=True,    # JavaScript 無法讀取
        secure=True,      # 只在 HTTPS 傳輸
        samesite='strict' # 防 CSRF 攻擊
    )
    return {"status": "success"}

5. 第三方 Script 要加 SRI & CSP 驗證(子資源完整性)

SRI 和 CSP 的差異:

  • CSP(Content Security Policy):控制「哪些來源」可以載入
  • SRI(Subresource Integrity):驗證「檔案內容」是否被竄改

兩者搭配使用最安全:

# 1. CSP:允許載入 cdn.example.com 的資源
response.headers['Content-Security-Policy'] = "script-src 'self' https://cdn.example.com"
<!-- 2. SRI:驗證載入的檔案沒被竄改 -->

<!-- ❌ 危險:直接載入第三方 Script -->
<script src="https://cdn.example.com/library.js"></script>
<!-- 問題:如果 CDN 被駭客入侵,惡意程式碼會直接執行 -->

<!-- ✅ 正確:加入 SRI 驗證 -->
<script
    src="https://cdn.example.com/library.js"
    integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/ux..."
    crossorigin="anonymous">
</script>
<!-- 如果 CDN 被駭改,檔案 hash 值不符,瀏覽器會拒絕執行 -->

如何取得 integrity 值?

# 使用 openssl 計算檔案的 hash
curl https://cdn.example.com/library.js | openssl dgst -sha384 -binary | openssl base64 -A

6. 不要把後端所有資料都丟給前端

# ❌ 危險:全部資料都傳給前端
@app.route('/api/users')
def get_users():
    users = db.query("SELECT * FROM users")
    return jsonify(users)  # 包含密碼、內部 ID、所有欄位!

# ✅ 正確:只傳必要欄位
@app.route('/api/users')
def get_users():
    users = db.query("SELECT id, name, email FROM users")
    return jsonify([{
        "id": u.id,
        "name": u.name,
        "email": u.email
        # 不傳:password_hash, internal_id, created_ip, etc.
    } for u in users])

7. 設定 security.txt(資安漏洞回報專線)

這是什麼?

security.txt 是一個國際標準格式的純文字檔(RFC 9116),專門讓資安研究員(白帽駭客)知道如何回報你網站的安全漏洞。

為什麼通常不會寫在一般的「聯絡我們」頁面?

一般聯絡頁面 security.txt
給一般用戶(客服諮詢) 給資安研究員(漏洞回報)
網頁格式,位置不固定 純文字,固定位置 /.well-known/security.txt
客服信箱處理 資安團隊直接處理
自動化工具無法掃描 全球統一格式,機器可讀

實際情境:

資安研究員發現你的網站有 SQL Injection 漏洞
    ↓
訪問 https://yoursite.com/.well-known/security.txt
    ↓
看到:Contact: security@yourcompany.com
    ↓
直接寄信給資安團隊(最直接)
    ↓
你立刻修復漏洞,避免被駭
# 要記得設定正確的 MIME Type
from fastapi import Response

@app.get("/.well-known/security.txt")
def security_txt():
    content = """Contact: mailto:security@yourcompany.com
Expires: 2026-12-31T23:59:59.000Z
Preferred-Languages: zh-TW, en"""

    return Response(content=content, media_type="text/plain")

重要: 即使是小網站也建議設定,這是資安研究員回報漏洞的標準管道。沒有它,研究員可能直接公開漏洞,導致你的網站被駭客攻擊。

8. 記錄存取紀錄

import logging
from datetime import datetime

def access_user_data(user_id, accessed_by):
    # 記錄誰在什麼時候存取了誰的資料
    logging.info(f"{datetime.now()} - {accessed_by} 存取了 {user_id} 的資料")
    # 這個 log 出事時有可能可以救你一命

9. 一定要有隱私權政策

如先前所說,再次複習,正確完整的網站免責聲明應該具備:

  1. 明確告知使用網站可能會有什麼風險
  2. 說明向用戶索取資料的用途與使用範圍
  3. 提供用戶選擇權(Yes/No)
  4. 確保使用者「確實看到並同意」,設計上應當確保「明顯提示」優先於「設計美感」,並且會有收費服務的地方應當再次提醒用戶此操作會扣款,這樣的做法在台灣法律來說是較為安全避免被究責的方式。
  5. 聯繫管道

讓AI幫你做資安檢查

既然都在用AI寫程式了,記得也請AI幫你檢查資安漏洞:

全面資安檢查Prompt參考範例

請以資安專家角度檢查這段程式碼,涵蓋以下面向:

**注入攻擊 (OWASP Top 1)**
- SQL Injection: 查詢是否參數化
- NoSQL Injection: MongoDB等查詢安全性
- Command Injection: 系統指令執行風險
- LDAP/XPath Injection

**身份驗證缺陷 (OWASP Top 2)**
- 弱密碼政策、預設帳密
- Session管理不當、JWT安全性
- 多因素驗證缺失
- 暴力破解防護

**敏感資料暴露 (OWASP Top 3)**
- 明文傳輸敏感資料
- 資料庫加密、備份安全
- 記錄檔包含敏感資訊
- 前端暴露後端資料

**XML/API安全**
- XXE (XML External Entity)
- API Rate Limiting
- CORS設定不當
- GraphQL安全問題

**存取控制缺陷**
- 垂直/水平權限提升
- 不安全的直接物件參考
- 檔案上傳漏洞
- Path Traversal

**安全設定錯誤**
- 預設設定、Debug模式
- 不必要的服務/功能
- Security Headers缺失
- 錯誤訊息過於詳細

**跨站攻擊**
- XSS (Stored/Reflected/DOM)
- CSRF Token缺失
- Clickjacking防護
- 不安全的Redirect

**已知漏洞元件**
- 第三方套件版本檢查
- CVE漏洞檢測
- 依賴套件安全性

**業務邏輯漏洞**
- 競態條件 (Race Condition)
- 工作流程繞過
- 數據驗證邏輯缺陷

**台灣法規合規 (個資法)**
- 資料收集目的說明
- 同意機制設計
- 資料遮蔽/假名化
- 資料保存期限

請指出具體風險點,提供修改建議,並標示風險等級

現有工具的資安功能

現在很多AI agent其實都有開始逐漸提供資安檢查的指令,可以多加善用(指令可能隨時更新,請以官方docs為主):

  • Claude Code: /sec 指令直接檢查檔案漏洞
  • GitHub Copilot: 註解 // @security-check 會建議安全寫法

重要: AI只能抓出明顯問題,複雜的業務邏輯漏洞還是需要人工審查。

AI醬的請求

親愛的工程師朋友,AI可能沒有辦法馬上想到要維護這些資安問題,請你永遠要記得提醒我、保護好自己:

  • 免責聲明不是免死金牌
  • 資安防護有最低限度的要求
  • 出事時沒人會因為你是新手而原諒你

當老闆或 PM 說「先上線再說」時,請勇敢地說:「至少要做基本的資安防護和隱私權聲明,不然出事我們都要負責。」


今日金句: "If your security strategy doesn't include people, it will fail." - Theresa Payton, Former White House CIO

明日預告: Day 20 - AI醬還在想~


上一篇
Day 18: Git 版本控制 - Vibe coding課程可能沒有教,很重要的事情
下一篇
Day 20: 善用 AI Agent 開發 - CV大師是你嗎?
系列文
AI醬的編程日記:我需要你教我的30件事21
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言