在上一篇我們完成了登入頁的組件化設計,讓程式碼更易於維護。既然基礎結構已經打好,接下來就能專心加入更進階的功能了🥳。
這一篇,我們要把表單驗證的部分徹底完成,延續 房門與門鎖[ 2 / 6 ]:React 生態系導入 — 表單驗證 & Router 分頁 的簡易表單驗證,加入 reCAPTCHA 驗證 與 密碼強度檢測。
本篇重點整理:
「我不是機器人🤖」這個詞是不是很熟悉呢?
這是 Google 開發的防機器人驗證功能,目前最常見的就是 reCAPTCHA v2 ( 核取方框 ),以及 v3 ( 隱形驗證 )。
它主要解決了什麼問題?
首先進入 Google reCAPTCHA 網站,登入後申請建立新網站:
localhost
申請完成後會得到 Site Key (公開金鑰) 與 Secret Key (秘密金鑰),兩者用途不同:
如果把秘密金鑰放到前端或公開到 GitHub,會有以下風險:
公開金鑰 (Site Key) → 安全地放在前端 React 元件中。
秘密金鑰 (Secret Key) → 放在後端環境變數,只用於伺服器與 Google API 溝通。
常見做法:
.env
檔案,例如:RECAPTCHA_SECRET_KEY=your-key
並在 .gitignore
中忽略 .env
,避免 push 到 GitHub。
就算通過 reCAPTCHA 機器人驗證,如果使用者輸入一個「123456」當密碼,那系統依然非常危險。
密碼強度驗證的目的是在使用者輸入時,立即提示密碼的安全等級,通常會依據以下規則檢測:
!@#$%^&*
等// validSchema.ts 部分程式碼
const passwordRegex = /^[a-zA-Z0-9!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?~]+$/;
常見做法有兩種:
type PasswordStrength = "None" | "Weak" | "Moderate" | "Strong" | "VeryStrong";
const checkPasswordStrength = (password: string): PasswordStrength => {
let strength = 0;
if (password.length >= 8) strength += 1; // 長度至少8
if (password.length >= 12) strength += 1; // 長度至少12
if (/[a-z]/.test(password)) strength += 1; // 包含小寫字母
if (/[A-Z]/.test(password)) strength += 1; // 包含大寫字母
if (/[0-9]/.test(password)) strength += 1; // 包含數字
if (/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?~]/.test(password)) strength += 1; // 包含特殊字元
if (password.length === 0) return "None";
if (strength <= 2) return "Weak";
if (strength <= 4) return "Moderate";
if (strength <= 5) return "Strong";
return "VeryStrong";
};
💡優點:快速、無需額外套件。
⚠️缺點:僅檢查格式,無法判斷密碼是否「常見弱密碼」。
import zxcvbn from "zxcvbn";
const result = zxcvbn("MyP@ssw0rd!2025");
console.log(result.score); // 0~4,越高越安全
console.log(result.feedback.suggestions); // 改進建議
答案是 會的,如果只有這樣的話🚨,因為:
前端驗證可被繞過
攻擊者可以直接用 Postman
或 cURL
發送請求,完全跳過前端的正則檢查。
Regex 只能檢查「格式」,不能檢查「強度」
例如 aaaaaaaa
符合正則,卻依然是超弱密碼。
真正的安全驗證必須在後端進行
後端應該再次檢查密碼規則,確保使用者無法繞過。
所以前端密碼強度檢查的意義在於:
✅ 提升使用者體驗(即時提示)
✅ 教育使用者設定更安全的密碼
❌ 不是安全保障的最終防線
最佳實踐是「前端做提示 + 後端做嚴格驗證」,兩邊都要有。
程式碼明日附上