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

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

毒舌时刻

这代码写得跟网红滤镜似的——仅供参考。

各位前端同行,咱们今天聊聊前端安全。别告诉我你还在写明文存储密码,那感觉就像把家门钥匙挂在门口——方便,但不安全。

为什么你需要前端安全

最近看到一个项目,登录表单直接把密码发送到服务器,没有任何加密。我就想问:你是在做应用还是在给黑客送大礼?

反面教材

// 反面教材:不安全的登录 // components/LoginForm.jsx export default function LoginForm() { const [username, setUsername] = useState(''); const [password, setPassword] = 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 }) // 明文密码 }); if (response.ok) { // 登录成功 } }; return ( <form onSubmit={handleSubmit}> <input type="text" value={username} onChange={(e) => setUsername(e.target.value)} placeholder="用户名" /> <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="密码" /> <button type="submit">登录</button> </form> ); } // 密码在网络传输中是明文 // 本地存储也是明文 

毒舌点评:这代码,密码明文传输,你是在写应用还是在做黑客培训?

前端安全的正确姿势

1. 密码加密

// 正确姿势:密码加密 // utils/auth.js import bcrypt from 'bcryptjs'; export async function hashPassword(password) { const salt = await bcrypt.genSalt(10); return await bcrypt.hash(password, salt); } export async function comparePassword(password, hashedPassword) { return await bcrypt.compare(password, hashedPassword); } // 服务端登录处理 // api/login.js export default async function handler(req, res) { const { username, password } = req.body; const user = await User.findOne({ username }); if (!user) { return res.status(401).json({ error: '用户不存在' }); } const isMatch = await comparePassword(password, user.password); if (!isMatch) { return res.status(401).json({ error: '密码错误' }); } // 生成 JWT token const token = generateToken(user.id); res.json({ token }); } 

2. XSS 防护

// 正确姿势:防止 XSS // components/Comment.jsx import DOMPurify from 'dompurify'; export default function Comment({ content }) { // 净化 HTML 内容 const sanitizedContent = DOMPurify.sanitize(content); return ( <div dangerouslySetInnerHTML={{ __html: sanitizedContent }} /> ); } // 服务器端设置 CSP 头 // next.config.js module.exports = { async headers() { return [ { source: '/(.*)', headers: [ { key: 'Content-Security-Policy', value: "default-src 'self'; script-src 'self' 'unsafe-inline' https://trusted-cdn.com" } ] } ]; } }; 

3. CSRF 防护

// 正确姿势:防止 CSRF // pages/api/protected.js import csrf from 'csurf'; const csrfProtection = csrf({ cookie: true }); export default function handler(req, res) { csrfProtection(req, res, () => { // 受保护的 API 逻辑 }); } // 客户端 // components/Form.jsx export default function Form() { const [csrfToken, setCsrfToken] = useState(''); useEffect(() => { // 获取 CSRF token fetch('/api/csrf-token') .then(res => res.json()) .then(data => setCsrfToken(data.token)); }, []); const handleSubmit = async (e) => { e.preventDefault(); await fetch('/api/protected', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': csrfToken }, body: JSON.stringify({ data: 'test' }) }); }; return ( <form onSubmit={handleSubmit}> <input type="hidden" name="_csrf" value={csrfToken} /> {/* 表单内容 */} </form> ); } 

毒舌点评:这才叫现代前端,安全第一,让黑客无处下手。

Read more

AI Skills:前端新的效率神器!

近来,AI 领域有个火爆的话题:Skills。 Github 上被疯狂 star 的仓库,很多都是和 skills 有关的。 有的仓库仅仅上线三个月就获得了快 50K 的 star,Skills 的火热可见一斑。 不管是大模型,还是 Cursor、Codex、Claude、Trae、Copilot 等编程 IDE 都在争先支持 Skills。 围绕 Skills,它们在做的就是为了完成一件事情:技能是通过学习和反复练习获得的,而 Skills 是把经验和最佳实践沉淀为 AI 能力,将“知道”转化为“做到”的本领。 详解什么是 Skills 要说清楚什么是 Skills,先来了解一下关于 AI 的 2

【Java Web学习 | 第三篇】CSS(2) - 元素显示模式

【Java Web学习 | 第三篇】CSS(2) - 元素显示模式

🌈个人主页: Hygge_Code🔥热门专栏:从0开始学习Java | Linux学习| 计算机网络💫个人格言: “既然选择了远方,便不顾风雨兼程” 文章目录 * CSS元素显示模式 * 2.1 什么是元素显示模式? * 2.2 三大核心显示模式详解 * 1. 块级元素(Block Level Elements) * 2. 行内元素(Inline Elements) * 3. 行内块元素(Inline-Block Elements) * 2.3元素显示模式的转换语法 * 1. 转为块级元素:`display: block` * 2. 转为行内元素:`display: inline` * 3. 转为行内块元素:`display: inline-block` * 2.4 实战案例:小米侧边栏实现 * 2.

Claude+Android Studio联动开发:我是如何用AI助手10分钟搞定WebView项目模板的

Claude+Android Studio联动开发:我是如何用AI助手10分钟搞定WebView项目模板的 上周三下午,产品经理突然丢过来一个需求:“下周一要演示一个内嵌H5页面的App原型,能不能先搭个架子?”我看了眼时间,距离下班只剩两小时。要在这么短的时间内从零开始搭建一个完整的Android WebView项目,还要处理好权限声明、Gradle依赖、网络配置这些琐碎但容易出错的部分,换作以前我肯定要加班到深夜。 但这次,我只用了十分钟。 不是因为我手速快,而是因为我找到了一个全新的工作流——让Claude这个AI助手帮我处理那些重复性的配置工作。整个过程就像有个经验丰富的搭档在旁边,你只需要告诉他你想要什么,他就能把代码、配置、甚至最佳实践建议都准备好。 如果你也在Android开发中遇到过类似的情况:每次新建项目都要反复查阅文档,担心漏掉某个关键权限,或者被Gradle版本兼容性问题搞得焦头烂额,那么这篇文章就是为你准备的。我会详细拆解如何通过自然语言指令,让Claude生成一个完整、可运行的WebView模块,并且补充那些官方文档很少提及的组件化实践细节。 1.

Go语言中的未来:从泛型到WebAssembly

Go语言中的未来:从泛型到WebAssembly 前言 作为一个在小厂挣扎的Go后端老兵,我对Go语言未来的理解就一句话:能进化的绝不固步自封。 想当年刚接触Go语言时,它还没有泛型,没有模块系统,甚至连错误处理都被人诟病。现在的Go语言已经今非昔比,泛型来了,模块系统完善了,错误处理也有了更多选择。 今天就聊聊Go语言的未来发展,从泛型到WebAssembly,给大家一个能直接抄作业的方案。 为什么需要关注Go语言的未来? 我见过不少小团队,只关注当前的技术,不关心语言的发展趋势,结果技术栈逐渐落后。关注Go语言的未来能带来很多好处: * 提前准备:了解未来的特性,提前调整代码结构 * 技术选型:根据未来趋势,做出更合理的技术选型 * 职业发展:掌握最新技术,提升个人竞争力 * 项目规划:根据语言发展,制定更合理的项目规划 泛型 泛型是Go 1.18引入的重要特性,它能让我们编写更加通用的代码。 基本用法 // 定义泛型函数 func Map[T, U any](s []T, f