為什麼新聞上總是有「XX公司會員資料外洩」?
當你學會了如何建立資料庫、如何把資料 JOIN 起來產生報表之後,你可能會覺得自己已經天下無敵,準備要幫客戶接案寫一個有會員系統的網站了。
請等一下!
如果你在這個時候,直接在你的 users 表格裡面新增一個叫做 password 的欄位,然後把使用者的密碼(例如 123456 或 iloveyou)以**「純文字 (Plain Text)」**的狀態存進去,那你將會犯下軟體工程界最嚴重、最不可原諒的資安大忌!
想像一下,如果你的資料庫被駭客入侵,或者是你的內部員工(甚至是剛離職的工程師)偷看了這張 users 表格。他們就能直接看到所有會員的密碼。
更可怕的是,有高達 80% 的人,他們在你的網站用的密碼,跟他的 Gmail、Facebook、銀行帳號密碼是一模一樣的。一旦你的網站外洩,駭客就能用這組密碼去盜用他所有的網路資產。
這就是為什麼,我們絕對不能在資料庫裡儲存「明文密碼」。
密碼的魔法:單向雜湊函數 (Hash Function)
要解決這個問題,全世界的資訊安全專家發明了一個超級魔法,叫做 「單向雜湊 (One-way Hash)」。
它的運作原理是這樣的:
當會員註冊,輸入了密碼 123456 時,你的網站程式 (例如 Node.js 或 Python) 不會直接把它存進資料庫。
相反地,程式會把這串密碼丟進一台「超級果汁機 (Hash Function,常見的演算法有 bcrypt 或 SHA-256)」裡面去打碎。
打碎之後,出來的果汁會變成一串毫無規律、長達 60 個字元的亂碼,例如:
$2b$12$eKx/n1Q1...
這時候,你只會把這串亂碼存進資料庫。
為什麼這叫「單向」?
因為這台果汁機是不可逆的。
就算世界上最聰明的駭客偷走了這串 $2b$12$eKx/n... 亂碼,他也無法用任何數學公式把它還原回原本的 123456。(就像你無法把一杯蘋果汁還原成一顆完整的蘋果一樣)。
那這樣會員下次登入時,要怎麼檢查密碼對不對?
當會員再次來到你的網站,輸入密碼 123456 準備登入時:
- 你的網站會再次啟動那台果汁機,把剛輸入的
123456打碎。 - 因為果汁機的設計是「同樣的蘋果,打出來的果汁一定長得一模一樣」。
- 你的網站只要去比對:這杯新打出來的果汁,跟資料庫裡存的那杯果汁,是不是完全一樣?
- 如果一樣,就代表密碼正確,允許登入!
整個過程中,你的資料庫從頭到尾都不知道會員的真實密碼是什麼。這就是現代身分驗證 (Authentication) 的絕對鐵則。
實戰:用 Vibe Coding 實作 Bcrypt 密碼加密
如果你要自己從頭寫這台果汁機,你需要非常深厚的密碼學與數學基礎。但在 Vibe Coding 的世界,這一切都只需要一句話。
假設你正在使用 Node.js / Express 開發後端 API,請在 Cursor 裡下達這個咒語:
【會員註冊與加密 Prompt】 我正在開發一個會員註冊的 API。請幫我寫一個處理註冊邏輯的 function。 流程如下:
- 接收前端傳來的
password。- 請使用
bcrypt套件,為密碼加上salt(salt rounds 設為 10),並進行 Hash 加密。- 將加密後的亂碼,連同 email 一起寫入 PostgreSQL 的
users表格。- 請附上完整的 Try-Catch 錯誤處理,並加上中文註解解釋 Bcrypt 的運作原理。
AI 產出的神級安全程式碼:
const bcrypt = require('bcrypt');
const db = require('./db'); // 假設這是你的資料庫連線模組
async function registerUser(email, plainPassword) {
try {
// 步驟 1: 設定加鹽的強度 (Salt Rounds),數值越大越安全,但運算越慢。10 是業界標準。
const saltRounds = 10;
// 步驟 2: 把明文密碼丟進果汁機打碎!這是一個非同步操作,會回傳加密後的字串。
const hashedPassword = await bcrypt.hash(plainPassword, saltRounds);
// 步驟 3: 把「加密後的亂碼」存進資料庫,千萬不能存 plainPassword!
const insertQuery = 'INSERT INTO users (email, password_hash) VALUES ($1, $2) RETURNING id';
const result = await db.query(insertQuery, [email, hashedPassword]);
console.log(`註冊成功!用戶 ID: ${result.rows[0].id}`);
return { success: true, message: '會員註冊成功' };
} catch (error) {
console.error('註冊過程中發生錯誤:', error);
return { success: false, message: '註冊失敗' };
}
}
這段由 AI 寫出的程式碼,完全符合業界最嚴苛的資安標準!就算你的資料庫被駭客整個拷貝帶走,駭客望著那堆 $2b$12... 的亂碼,也只能欲哭無淚。
JWT (JSON Web Token):登入後的通行證
當會員成功比對完果汁機密碼、順利登入之後,接下來會發生什麼事?
難道會員每點擊一個網頁(例如:進入購物車、查看個人檔案),都要重新輸入一次密碼嗎?當然不是。 當會員登入成功的那一瞬間,你的伺服器會發給會員一張 「VIP 數位通行證」。這張通行證在現代網頁開發中,最主流的技術就叫做 JWT (JSON Web Token)。
這張通行證會被悄悄地存在瀏覽器的某個角落 (例如 LocalStorage 或 Cookie)。 之後會員每次對你的網站發出請求(例如:「我要看我的購物車」),瀏覽器就會自動把這張通行證夾在請求裡面發送過去。 伺服器只要驗證這張通行證是真的(沒有被偽造、也沒有過期),就會直接放行,把購物車的資料吐回來給會員。
在 Vibe Coding 實戰中,你同樣不需要自己去拼湊 JWT 的字串。
【Vibe 咒語提示】:「請使用
jsonwebtoken套件,實作一個登入驗證的 Middleware。在登入成功後核發一個效期為 7 天的 JWT token。」
透過 Hash 保護密碼、透過 JWT 發行通行證。這兩個資安護城河,是所有商業級全端應用的基石。但在接下來的最後一章,我們將介紹 Supabase 特有的一種終極防禦武器:RLS (行級安全控制)。它將徹底顛覆你對資料庫安全的想像!