密码"qwerty123"不再有效:为什么安全并不无聊
想象一下:您编写了一个很棒的Web应用程序。漂亮的界面、响应式代码,一切运行流畅。您启动它,注册第一个用户——一小时后,您的数据库就泄露到了公共领域。听起来很熟悉?不幸的是,JavaScript中的安全认证是许多开发人员推迟处理的话题。但这是错误的。
在本文中,我们将探讨如何保护您的应用程序免受最常见的攻击:令牌拦截、XSS、CSRF和密码泄露。我们不会进行关于"应该做好"的说教——我们将展示您可以立即使用的代码。
准备好了吗?开始吧。
JavaScript中的认证:为什么客户端是战场
当我们谈论Web认证时,我们经常想到后端:数据库、会话、哈希。但JavaScript认证始于客户端。而这里隐藏着陷阱。
在浏览器中运行的一切都可能被读取、修改或窃取。如果攻击者找到了漏洞,您的JavaScript代码就是一本打开的书。因此,安全认证的第一条规则是:永远不要信任客户端。永远不要。
客户端的主要威胁
- XSS(跨站脚本攻击)——攻击者注入脚本,窃取localStorage中的令牌。
- CSRF(跨站请求伪造)——用户已登录,恶意网站代表用户发送请求。
- 中间人攻击——如果未使用HTTPS,则拦截流量。
- 密码泄露——以明文形式发送密码或将其存储在代码中。
听起来很可怕?实际上,防御这些攻击并不那么困难。关键是要知道使用哪些工具。
JWT:方便但有陷阱
JWT(JSON Web令牌)是创建访问令牌的标准。它轻量级,无需在服务器上存储,非常适合SPA。但它的流行使其成为攻击目标。
许多开发人员将JWT存储在localStorage中。这是一个错误。localStorage可以从页面上的任何JavaScript代码访问。如果您至少有一个XSS漏洞——令牌就会被窃取。
如何正确存储JWT
最好的方法是httpOnly Cookie。带有httpOnly标志的Cookie对JavaScript不可访问。XSS无法窃取它们。但有一个问题:Cookie会随每个请求自动发送,这使得应用程序容易受到CSRF攻击。解决方案是使用SameSite和CSRF令牌。
以下是在后端(Node.js与Express)设置httpOnly Cookie的示例:
// 服务器(Node.js / Express)res.cookie('token', jwtToken, { httpOnly: true, // 对JavaScript不可访问 secure: true, // 仅通过HTTPS sameSite: 'strict', // 防御CSRF maxAge: 3600000 // 1小时});在客户端,您只需发送请求——Cookie会自动附加:
// 客户端(JavaScript)fetch('/api/profile', { method: 'GET', credentials: 'include' // 必须!}).then(res => res.json()).then(data => console.log(data));请注意:credentials: 'include'——没有这个,Cookie不会发送到其他源。
密码哈希:bcrypt为您提供帮助
以明文形式存储密码就像把家门钥匙放在门垫下。即使您的网站被黑客攻击,密码也应该对攻击者毫无用处。
bcrypt是一种专门设计为慢速的哈希算法。因为为用户哈希密码只需几分之一秒,而破解则需要数年。在JavaScript(Node.js)中,使用b