Build a Membership System with Express.js Session
使用 Express.js Session 实作会员系统
前言
根据先前的教学,我们已经可以创建基本的 CRUD 程式,但基于 HTTP 是无状态的协议,如果单纯实作会员系统,用户将会需要在每次操作登入会员相关的行为时重复验证,明显是糟糕的使用体验。
一种解决方案是在请求时伺服器将会建立 Session (存储在伺服器端的一笔数据),而用户会从回应拿到一组 session ID,通常存放于 Cookie 当中,伺服器透过这个 ID 来识别和定位特定用户的 session 资料,这样一来伺服器就能记住个别用户相关的对应资料。
Session 储存
具体来说 express-session 是常用的套件帮助我们实践伺服器 Session。建议阅读官方文件进一步设置,像是:
name
: 可自订 cookie 名称,避免使用预设的connect.sid
cookie.httpOnly
: 预设为true
,但建议明确说明cookie.sameSite
: 建议设为strict
增加安全性- …
最小范例
根据 Express.js 入门 创建一个简单的后端伺服器,并且安装express-session
协助我们建构 Session 记忆用户,预设会储存在记忆体中,实际可能会连结到文件系统、资料库或分散式储存,Session 的储存机制并没有一定。
如上就是一个最小范例,当用户访问首页时会计算用户访问次数,并且将次数存放在 session 中,如果用户再次访问时会增加次数。
登入系统
- 注册页面
/register
:用户输入帐号和密码,伺服器验证帐号是否已存在,若不存在则注册成功。 - 登入页面
/login
:使用者输入帐号和密码。 - 登入处理
/login
:伺服器验证帐密,若正确则在 session 中设置isLoggedIn
状态和username
。 - 个人资料页面
/profile
:根据是否登入来决定是否显示用户资料还是跳转到登入页。 - 登出
/logout
:销毁 session 并清除 cookie。
我将专案放到 GitHub - express-in-memory-session 上,可以下载下来玩玩看。
安全最佳实践
- 使用 HTTPS:加密传输过程中的 session ID,避免中间人攻击。
- 设定HttpOnly 和[Secure Cookie](https://developer.mozilla.org/en-US/docs/Web/Security/Practical_implementation_guides/Cookies# secure):防止 JavaScript 读取 session ID,并确保仅 HTTPS 传输。
- Session 过期时间:设置合理的 session 过期时间,例如 15 分钟未操作后过期。
- 重新生成 Session ID:在登入和登出时重新生成 session ID,防止 Session Fixation 攻击。
密码加密
密码应储存为加密形式(例如使用 bcrypt),通过哈希算法将密码转换为不可逆的数据,未来验证时也同样将用户输入的密码进行哈希后再进行比对,如此一来就算密码数据库外泄也不会直接暴露用户密码。
为了保护哈希值的唯一性,bcrypt 默认帮你生成一个随机的「盐」并附加在密码后面,这样即使两个用户密码相同,哈希值也不会相同,提高了破解难度。
延伸阅读
- Your complete guide to understanding the express-session library - Zach Gollwitzer
- HTTP Session 攻擊與防護 - DEVCORE Allen Own
- 寫給網頁開發者的 CSRF 理解與防範 - WebDong