前端安全相关

XSS

跨站脚本攻击(XSS,Cross - Site Scripting) 攻击者通过在目标网站中注入恶意脚本,来获取用户的敏感信息、执行恶意操作等。这些恶意脚本通常是 JavaScript

本质上就是在任何前端js可能读取的地方插入恶意脚本

整体过程

攻击者提交恶意代码 -> 浏览器执行恶意代码

反射型XSS

示例:一个简单的搜索功能,用户在搜索框输入内容后,服务器将用户输入的内容直接在页面上显示。攻击者构造一个类似 http://example.com/search?q=<script>alert('XSS')</script> 的 URL,当用户点击这个链接,就会弹出一个警告框显示 “XSS”。

存储型XSS

原理:攻击者将恶意脚本存储在目标服务器上,如存储在数据库、文件系统等。当其他用户访问包含该恶意脚本的页面时,浏览器就会执行这个脚本。这种类型的 XSS 通常出现在用户可以提交内容并且这些内容会被长期存储和展示的场景中,比如论坛、博客的评论区等。
示例:在一个论坛系统中,攻击者在评论区提交一个包含恶意脚本 <script>stealCookie()</script>(假设存在一个名为 stealCookie 的恶意函数)的评论。当其他用户查看这个评论时,他们的浏览器会执行这个脚本,导致他们的 Cookie 信息可能被窃取。

DOM型XSS

原理:这种类型的 XSS 是由于 HTML 页面中,JavaScript 通过 DOM 操作动态地修改页面内容而导致的。攻击者利用 JavaScript 代码中的漏洞,修改 DOM 来注入恶意脚本。与前面两种不同的是,它不依赖于服务器端对数据的反射或者存储,而是完全在客户端浏览器环境中发生。
示例:有一个网页,其中有一段 JavaScript 代码如下:

1
document.getElementById('userInput').innerHTML = location.hash.substr(1);

攻击者可以构造一个 URL,如 http://example.com/page.html#<script>alert('XSS')</script>,当用户访问这个 URL 时,浏览器会执行这个恶意脚本,弹出警告框。

预防漏洞的思路

  • 前端提交时过滤(请求可以绕过前端)
  • 后端过滤(不能预防dom型XSS)
  • 前端渲染时转义(完美)

其他安全措施

CSP内容安全策略(Content Security Policy):

详细可见:使用严格的内容安全政策 (CSP) 缓解跨站脚本攻击 (XSS)

  • 禁止内联脚本的执行
  • 只加载信任域名的外联JS
  • 禁止 eval
  • 禁止 form 提交到第三方
    CSP设置方式
  • Nginx 返回Html文件的响应头设置
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    server {
    listen 80;
    server_name your-domain.com; # 你的域名
    root /usr/share/nginx/html; # 前端静态资源目录

    # 核心:设置 CSP HTTP 头(Vue/React 通用基础规则)
    add_header Content-Security-Policy "
    default-src 'self'; # 默认只允许同域
    script-src 'self' https://cdn.jsdelivr.net; # JS 允许同域 + 指定 CDN
    style-src 'self' 'unsafe-inline'; # 样式允许同域 + 内联(兼容大部分项目)
    img-src 'self' data:; # 图片允许同域 + base64
    connect-src 'self' https://api.your-domain.com; # 接口允许同域 + 后端接口
    font-src 'self'; # 字体允许同域
    object-src 'none'; # 禁止插件(如 flash)
    frame-ancestors 'none'; # 禁止被嵌入 iframe(防点击劫持)
    ";

    # 其他 Nginx 配置(静态资源/路由等)
    location / {
    try_files $uri $uri/ /index.html;
    }
    }
  • Html文件meta标签设置
    1
    2
    3
    4
    <meta 
    http-equiv="Content-Security-Policy"
    content="default-src 'self';script-src 'self' https://cdn.example.com;"
    >

禁止 JavaScript 读取某些敏感 Cookie,攻击者完成 XSS 注入后也无法窃取此 Cookie。

验证码

防止脚本冒充用户提交危险操作。


CSRF

CSRF(Cross-site request forgery)跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。

本质上是因为浏览器有cookie这么个东西,并且针对同一个域名的请求会自动带上cookie

一个典型的CSRF攻击有着如下的流程:

  • 受害者登录a.com,并保留了登录凭证(Cookie)。
  • 攻击者引诱受害者访问了b.com。
  • b.com 向 a.com 发送了一个请求:a.com/act=xx。浏览器会默认携带a.com的Cookie。
  • a.com接收到请求后,对请求进行验证,并确认是受害者的凭证,误以为是受害者自己发送的请求。
  • a.com以受害者的名义执行了act=xx。
  • 攻击完成,攻击者在受害者不知情的情况下,冒充受害者,让a.com执行了自己定义的操作。

预防漏洞的思路

阻止不明外域的访问

同源检测、Samesite Cookie

  • Samesite Cookie = Strict
    同源请求才会带上cookie
  • Samesite Cookie = Lax
    条件放宽,某些不同源的请求也会带上cookie,比如get请求,访问一个页面链接时。因为一般不会使用get请求修改数据,安全性较高
  • Samesite Cookie = None
    不管是否同源请求都会带上cookie,只在cookie设置为secrue时生效(非https协议不会传cookie)
提交时要求附加本域才能获取的信息

CSRF Token、双重Cookie验证

一种详细的web端方案是前端存储 CSRF Token + 请求头 / 参数携带:

  1. 后端生成并下发 CSRF Token(两种方式下发)

    存在「非 HttpOnly 的 Cookie」中(让前端能读取);
    或返回给前端,让前端存在 localStorage

  2. 前端读取 CSRF Token 并携带到请求中
    前端从 Cookie 读取 CSRF Token,在请求头 / 参数中携带(不能放在 Cookie 中,否则会被自动携带,失去意义)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // 前端日常请求(复用已有的 CSRF Token)
    function updateUserInfo() {
    // 读取登录时下发的 CSRF Token(一直存在 Cookie 中,直到登出/过期)
    const csrfToken = getCsrfToken();
    fetch('/api/update', {
    method: 'POST',
    headers: {
    'X-CSRF-Token': csrfToken, // 复用 Token
    'Content-Type': 'application/json'
    },
    body: JSON.stringify({ nickname: '新昵称' })
    });
    }

这种方案能实现防护的一个根本原因是同源策略不允许跨域的读取Cookie,也就是说攻击者的站点做不到用js跨域的从我们网站读取cookie来伪造请求

A 网站的 JS 只能读取 A 网站的 Cookie / 存储,绝对无法读取 B 网站的 Cookie / 存储。

同源策略详细可见:同源与跨域