當自己想要製作一個網頁並實現登入功能時,是否曾經面對過這樣的疑問呢?
平常我們習以為常的登入功能,其背後其實隱藏著一些不為人知的原理。本文將解釋登入認證的基本機制。
其實,HTML/CSS 本身並不具備確認登入狀態的功能。更精確地說,因為網路的基礎 HTTP 協議本身是「無狀態的」。
HTTP 為每個從客戶端(瀏覽器)發出的請求進行獨立的通訊。也就是說:
這兩個請求在 HTTP 的運作上被視為完全無關的獨立通訊。伺服器無法自動識別「剛才訪問的人與現在的是同一個人」。

這樣一來就無法維持「登入狀態」。那麼,實際的網站是如何維持登入狀態的呢?
答案在於 Cookie(曲奇)與 Session 管理。
Cookie 是由伺服器發送到瀏覽器的小數據,並保存於瀏覽器中。重要的是,瀏覽器會在下次請求時自動將存儲的 Cookie 發送回伺服器。
利用這個機制來維持「登入狀態」。
讓我們來看看具體的流程。

「登入後的頁面如果直接輸入網址,是否會不需登入就能進入?」這個問題透過 伺服器端的 Session 驗證來解決。
這樣就能持續判定是否已登入,未認證的使用者將被攔截於受保護的頁面之外。
在了解登入的機制後,還需談及一些關鍵的安全問題。
如果存在安全漏洞,可能會被他人冒充或導致個人資訊被竊取。
實作運行與安全是兩回事,因此自一開始就必須具備安全性的設計意識。
如果將密碼直接(明文)保存於資料庫中:
-- ❌ 絕對不應該這樣做的例子
INSERT INTO users (email, password)
VALUES ('[email protected]', 'mypassword123');
這樣做會導致:
密碼應使用 哈希函數 進行單向轉換(哈希化)後再保存。
對於不太了解哈希化的人,可以簡單記住,「以無法回覆的形式進行轉換」。
加密是可解密的,而哈希化是單向轉換無法解密的。
// 擬似代碼例
const bcrypt = require('bcrypt');
// 使用者註冊時
const password = 'mypassword123';
const saltRounds = 10;
const passwordHash = await bcrypt.hash(password, saltRounds);
// 保存至資料庫
db.query(
'INSERT INTO users (email, password_hash) VALUES (?, ?)',
['[email protected]', passwordHash]
);
// 保存的例子:$2b$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
Cookie 中僅能保存 Session ID,不應保存個人資訊或機密信息。
若將個人資訊或機密情報放在裡面,每次都會被發送到網絡上,增加洩露的風險。
如果 httpOnly 未設置,JavaScript 可能會被竊取;若未設置 secure,則可能在非 HTTPS 的路徑中洩露。
因此,Cookie 也需設置適當的安全選項,將機密信息保存於資料庫中。
| 選項 | 說明 |
|---|---|
httpOnly |
禁止 JavaScript 訪問(防範 XSS) |
secure |
僅在 HTTPS 通信中發送 Cookie |
sameSite |
限制跨網站請求中的 Cookie 發送(防範 CSRF) |
maxAge |
設定 Cookie 的有效期限 |
Session ID 必須透過 HTTPS 發送,否則在中間人攻擊中可能會被竊取。
HTTP 通信沒有加密,即便最終的形式經過加密,但若在途中被竊取,機密信息仍會洩露。
Session 劫持是指竊取 Session ID 然後冒充正規使用者的攻擊。
即便密碼安全,若 Session ID 被得知,仍可訪問受保護的頁面。
正如前面所述,Session ID 是由 Cookie 管理的,因此安全性相較於密碼要低。
因此,對於 Session ID 我們還需採取如下的安全對策。
原文出處:https://qiita.com/shibata1111/items/855524191d08f73a6748