前端安全:别让你的网站变成黑客的游乐场

前端安全:别让你的网站变成黑客的游乐场

毒舌时刻

这代码写得跟筛子似的,到处都是漏洞。

各位前端同行,咱们今天聊聊前端安全。别告诉我你还在忽略安全问题,那感觉就像在没有锁的房子里放贵重物品——能放,但随时可能被偷。

为什么你需要关注前端安全

最近看到一个项目,直接在前端存储用户密码,没有任何加密措施。我就想问:你是在做网站还是在做慈善?

反面教材

// 反面教材:不安全的代码 function Login() { const [username, setUsername] = React.useState(''); const [password, setPassword] = React.useState(''); const handleSubmit = async (e) => { e.preventDefault(); // 直接发送密码,没有加密 const response = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }) }); const data = await response.json(); // 直接存储 token 在 localStorage localStorage.setItem('token', data.token); }; return ( <form onSubmit={handleSubmit}> <input type="text" placeholder="用户名" value={username} onChange={(e) => setUsername(e.target.value)} /> <input type="password" placeholder="密码" value={password} onChange={(e) => setPassword(e.target.value)} /> <button type="submit">登录</button> </form> ); } export default Login; 

毒舌点评:这代码,就像在大街上裸奔,一点隐私都没有。

正确姿势

1. 密码安全

// 正确姿势:密码安全 // 1. 使用 HTTPS // 2. 密码加密传输 function Login() { const [username, setUsername] = React.useState(''); const [password, setPassword] = React.useState(''); const handleSubmit = async (e) => { e.preventDefault(); // 使用 HTTPS 传输 const response = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }) }); const data = await response.json(); // 使用 httpOnly cookie 存储 token // 服务端设置: res.cookie('token', token, { httpOnly: true, secure: true }); }; return ( <form onSubmit={handleSubmit}> <input type="text" placeholder="用户名" value={username} onChange={(e) => setUsername(e.target.value)} /> <input type="password" placeholder="密码" value={password} onChange={(e) => setPassword(e.target.value)} /> <button type="submit">登录</button> </form> ); } export default Login; 

2. XSS 防护

// 正确姿势:XSS 防护 // 1. 使用 dangerouslySetInnerHTML 时要小心 // 2. 对用户输入进行转义 function CommentList({ comments }) { return ( <div> {comments.map(comment => ( <div key={comment.id}> {/* 安全的方式:直接渲染文本 */} <p>{comment.content}</p> {/* 不安全的方式 */} {/* <p dangerouslySetInnerHTML={{ __html: comment.content }} /> */} </div> ))} </div> ); } // 后端转义 // server.js app.post('/api/comments', (req, res) => { const { content } = req.body; // 转义用户输入 const escapedContent = escapeHtml(content); // 存储转义后的内容 db.insert({ content: escapedContent }); res.json({ success: true }); }); function escapeHtml(text) { return text .replace(/&/g, '&amp;') .replace(/</g, '&lt;') .replace(/>/g, '&gt;') .replace(/"/g, '&quot;') .replace(/'/g, '&#039;'); } 

3. CSRF 防护

// 正确姿势:CSRF 防护 // 1. 使用 CSRF token // 2. 验证 Origin/Referer 头 function Form() { const [csrfToken, setCsrfToken] = React.useState(''); React.useEffect(() => { // 从服务端获取 CSRF token async function getCsrfToken() { const response = await fetch('/api/csrf-token'); const data = await response.json(); setCsrfToken(data.token); } getCsrfToken(); }, []); const handleSubmit = async (e) => { e.preventDefault(); const response = await fetch('/api/submit', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': csrfToken }, body: JSON.stringify({ /* 表单数据 */ }) }); const data = await response.json(); console.log(data); }; return ( <form onSubmit={handleSubmit}> <input type="hidden" name="_csrf" value={csrfToken} /> {/* 表单字段 */} <button type="submit">提交</button> </form> ); } // 服务端验证 // server.js app.post('/api/submit', (req, res) => { const csrfToken = req.headers['x-csrf-token'] || req.body._csrf; if (!csrfToken || !validateCsrfToken(csrfToken)) { return res.status(403).json({ error: 'CSRF token invalid' }); } // 处理请求 res.json({ success: true }); }); 

4. 依赖安全

// 正确姿势:依赖安全 // 1. 定期更新依赖 // 2. 使用 npm audit 检查漏洞 // 3. 使用 Snyk 等工具监控 // package.json { "name": "my-app", "version": "1.0.0", "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0" }, "scripts": { "audit": "npm audit", "update": "npm update" } } // 运行命令 // npm run audit // npm run update 

毒舌点评:这才叫前端安全,让你的网站固若金汤,再也不用担心黑客攻击了。

Read more

Cursor实战:Web版背单词应用开发演示

Cursor实战:Web版背单词应用开发演示

Cursor实战:Web版背单词应用开发演示 * 需求分析 * 自行编写需求文档 * 借助Cursor生成需求文档 * 前端UI设计 * 后端开发 * 项目结构 * 环境参数 * 数据库设计 * 安装Python依赖 * 运行应用 * 前端代码修改 * 测试前端界面 * 测试数据生成 * 功能测试 * Bug修复 * 总结 在上一篇《Cursor AI编程助手不完全指南》中,我们详细介绍了Cursor这款强大的AI编程工具。为了让大家能更直观地了解 Cursor 的实战应用价值,本文将通过一个实际项目来展示其开发流程。我们将使用 Cursor 开发一个 Web 版单词学习程序,通过这个案例,您将看到 AI 辅助开发的完整过程,体验从需求分析到代码实现的全过程。让我们开始这次实战之旅。 需求分析 在开始开发之前,明确的需求文档是项目成功的关键。一个好的需求文档不仅能指导开发方向,还能作为与 Cursor 进行高效对话的重要基础。我们有两种方式来准备需求文档:自行编写需求文档和借助 Cursor 生成需求文档

前端老哥必看:鼠标横向滚动条卡死?3招搞定滚动方向反人类难题

前端老哥必看:鼠标横向滚动条卡死?3招搞定滚动方向反人类难题

前端老哥必看:鼠标横向滚动条卡死?3招搞定滚动方向反人类难题 * 前端老哥必看:鼠标横向滚动条卡死?3招搞定滚动方向反人类难题 * 开头先吐槽两句这该死的交互体验 * 扒一扒浏览器原生滚动的那些坑爹设定 * 横向滚动条这"社恐"属性 * 鼠标滚轮的"偏科"问题 * 浏览器们的"塑料姐妹情" * 手把手教你用代码强行"掰正"滚动方向 * 扔掉 jQuery,原生 JS 真香 * 防抖节流必须安排 * 方向判断的智能处理 * 横向滚动条到底该不该秀出来这是个问题 * 隐藏 vs 显示的永恒纠结 * 跨平台样式统一大作战 * 移动端和桌面端得分家 * 真实项目里那些让人哭笑不得的翻车现场 * 时间轴事件的"原地起飞" * 嵌套滚动的"世界大战" * 动态内容的&

浏览器 Web Bluetooth API使用方法

浏览器 Web Bluetooth API使用方法

浏览器 Web Bluetooth API 完整指南 一、简介 什么是 Web Bluetooth API? Web Bluetooth API 让网页应用可以与蓝牙设备通信。通过这个 API,你可以: * 👂 扫描并连接蓝牙设备 * 📤 发送命令到设备 * 📥 接收数据从设备返回 * ⚙️ 控制设备的各种操作 适用场景 医疗设备、手环、手表、传感器、遥控器、音箱、灯等 ↓ 所有支持蓝牙的设备都可以通过这个 API 与网页应用通信 浏览器支持 浏览器支持最低版本Chrome/Edge✅56+ / 79+Firefox⚠️ 需启用98+Safari❌- 二、核心概念(5 分钟快速理解) 2.1 蓝牙通信的三层结构 物理设备(