iT邦幫忙

2026 iThome 鐵人賽

DAY 5
0
Security

新手開發者的資安第一課:30 天搞懂 OWASP Top 10 與常見漏洞系列 第 5

Day 05:身分認證漏洞––弱密碼暴力破解與缺乏多因素驗證(MFA)的危機

  • 分享至 

  • xImage
  •  

在昨天的文章中,我們探討了「授權(Authorization)」問題——也就是使用者進入系統後能做什麼。今天我們要回到更前方的關卡:「認證(Authentication)」——系統如何確定「你真的就是你」?

在 OWASP Top 10 中,身分驗證與認證失敗(Identification and Authentication Failures) 長期霸榜。如果身分驗證防線崩潰,攻擊者不用尋找複雜的程式碼漏洞,只要拿著正確的帳號密碼,就能像合法使用者一樣大搖大擺地登入系統。

什麼是弱密碼與暴力破解?

想像你家的大門鎖只使用了預設的 0000 或 1234(弱密碼),甚至門口站著一個小偷,正拿著一串包含數百萬把鑰匙的巨大鑰匙圈,一秒鐘試幾十把鎖(暴力破解)。如果你的門鎖沒有「連續錯 5 次就自動鎖住」的機制,門被打開只是時間問題。何況在現實世界中,攻擊者不會一組一組密碼慢慢猜,而是透過自動化腳本與專屬工具進行攻擊

攻擊方式解析

瞭解攻擊者如何破解密碼,是設計安全認證機制的第一步:

  • Brute Force Attack(傳統暴力破解攻擊):自動化程式從 a 到 zzzzzz,嘗試所有可能的字元組合。雖然耗時,但若密碼極短,可在幾秒內破解。

  • Dictionary Attack(字典攻擊):利用事先整理好的「常用密碼清單」(如 123456, password, admin)進行快速比對。大部分使用者設定的弱密碼都會落在字典檔中。

  • Credential Stuffing(憑證填充 / 撞庫攻擊):攻擊者收集其他網站洩漏的「帳號/密碼」組合,自動套用到各大熱門網站(如 GitHub、AWS、公務系統)嘗試登入。這是因為高達 60% 以上的使用者會在不同網站重複使用相同密碼。

  • Password Spraying(密碼噴射攻擊):為了避開「單一帳號連續失敗 5 次就鎖定」的防禦機制,攻擊者轉為對大量不同的帳號,只嘗試 1~2 個極常見的密碼(例如 Spring2026! 或 Company2026!)。這樣既能保持低失敗頻率,又能掃出一堆弱密碼帳號。

  • Rainbow Table Attack(彩虹表攻擊):當資料庫被洩漏時,若密碼雜湊值(Hash)沒有加上 Salt(鹽值),攻擊者可利用雜湊對照表(彩虹表)還原出原始密碼。

實務情境

情境:登入 API 的驗證機制與限制
無限制且未驗證 MFA


# 完全沒有限制嘗試次數、無防護機制,且僅依靠單一密碼驗證
@app.route('/api/v1/login', methods=['POST'])
def login():
    username = request.json.get('username')
    password = request.json.get('password')
    
    user = db.find_user(username)
    # 直接比對明文密碼,且登入失敗完全不記錄、不計數
    if user and user.password == password:
        return jsonify({"status": "success", "token": generate_token(user)})
    
    return jsonify({"status": "failed", "message": "Invalid credentials"}), 401

強認證 + 限流 + MFA 驗證

# 正確:實施速率限制 (Rate Limiting)、密碼雜湊比對與 MFA 驗證
from flask_limiter import Limiter
from werkzeug.security import check_password_hash

# 1. 對登入 API 實施 IP 與帳號等級的連線限流
@limiter.limit("5 per minute")
@app.route('/api/v1/login', methods=['POST'])
def login():
    username = request.json.get('username')
    password = request.json.get('password')
    mfa_code = request.json.get('mfa_code')  # 多因素驗證碼
    
    user = db.find_user(username)
    
    # 2. 檢查帳號是否因多次失敗而被暫時鎖定 (Lockout)
    if is_account_locked(username):
        return jsonify({"message": "Account temporarily locked. Try again later."}), 429
        
    # 3. 使用安全雜湊(hash)演算法 (如 bcrypt/Argon2) 比對密碼
    if not user or not check_password_hash(user.password_hash, password):
        record_failed_attempt(username)
        return jsonify({"message": "Invalid credentials"}), 401

    # 4. 強制第二階段身分驗證 (MFA Check)
    if not verify_mfa_totp(user.mfa_secret, mfa_code):
        return jsonify({"message": "Invalid MFA Code"}), 401

    reset_failed_attempts(username)
    return jsonify({"status": "success", "token": generate_token(user)})

如何正確建構強健的身分驗證防線?

要防禦自動化密碼攻擊,必須從政策與技術層面雙管齊下:

  1. 強制導入多因素驗證(Multi-Factor Authentication,MFA)
  • TOTP (Time-based One-Time Password): 使用 Google Authenticator、Authy 等 APP 生成每 30 秒更換一次的動態驗證碼
  • FIDO2 / WebAuthn: 結合硬體金鑰或裝置生物辨識,達成抵禦釣魚與撞庫的最高等級防護。
  1. 部署 Rate Limiting(速率限制)與 Account Lockout(帳號鎖定)
  • 設定登入 API 門檻,例如:同一 IP 或同一帳號 1 分鐘內失敗超過 5 次,即封鎖 15 分鐘。
  1. 正確的密碼儲存機制(Password Hashing)
  • 嚴禁明文儲存密碼!
  • 必須使用具備適應性耗時(Work Factor)與自動加鹽(Salting)的演算法:Argon2id、bcrypt 或 PBKDF2,大幅增加攻擊者離線破解的成本

自動加鹽(Salting):
當使用者設定密碼(例如 password123)時,系統會在後端隨機產生一串極長的隨機字串(稱為 Salt,鹽值),將「鹽值 + 密碼」組合在一起後,再丟進雜湊函數進行計算。最後把這個「鹽值」與「計算出的 Hash」一起存入資料庫。

適應性耗時 / 工作因子:
傳統的雜湊演算法(如 MD5, SHA-1, SHA-256)設計初衷是為了「極速計算」,這對密碼儲存來說反而成了致命傷(現代顯示卡 GPU 每秒可計算數百億次 SHA-256)。適應性耗時(Work Factor) 允許開發者設定「演算法內部的迴圈迭代次數」或「記憶體消耗量」。計算一次 Hash,故意要求 CPU/GPU 強制執行數萬次的重複計算。


上一篇
Day 04:存取控制缺陷----過度授權與特權帳號風險
下一篇
Day 06:營運中斷風險––缺乏備援(RTO/RPO)與營運持續計畫(BCP)漏洞
系列文
新手開發者的資安第一課:30 天搞懂 OWASP Top 10 與常見漏洞10
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言