认识和防御 XSS 和 CSRF 攻击 | 青训营

1,317 阅读7分钟

概述

在现代 Web 应用程序中,安全性是至关重要的。两种常见的安全威胁是 XSS(跨站脚本攻击)和 CSRF(跨站请求伪造)。了解它们的工作原理以及如何防御这些攻击非常重要。本文将介绍 XSS 和 CSRF 的基本知识,并提供一些示例和防御方法。

一、XSS(跨站脚本攻击)

XSS 是一种攻击技术,攻击者通过注入恶意代码,使用户的浏览器执行这些恶意代码。XSS 分为三种类型:反射型(非持久型)、存储型(持久型)和基于 DOM。攻击者利用 XSS 攻击可以窃取用户的敏感信息、劫持前端逻辑或发送任意请求。

image.png

1. XSS 分类

  • 反射型 XSS 攻击

    反射型 XSS 是通过注入恶意代码到 URL 参数中,然后将其反射到页面上。例如,攻击者可以构造一个恶意的 URL,当用户点击该 URL 时,恶意代码会被执行。

image.png

  • 存储型 XSS 攻击

    存储型 XSS 是将恶意代码存储到目标网站的数据库中,当用户访问包含恶意代码的页面时,代码会从数据库中加载并执行。

image.png

  • 基于 DOM 的 XSS 攻击

    基于 DOM 的 XSS 攻击是通过修改页面的 DOM 结构来执行恶意代码。攻击者可以利用未正确验证的用户输入直接修改 DOM,从而实现攻击目的。

image.png

2. XSS 一些特点

image.png

3. 防御 XSS 攻击

防御 XSS 攻击的关键是对用户的输入进行过滤和转义。以下是一些防御 XSS 攻击的方法:

  • 对用户输入进行合理的验证和过滤,确保只接受预期的数据格式,并拒绝具有潜在恶意的数据。

    function sanitizeInput(input) {
      // 通过使用合适的正则表达式或其他方法,确保输入符合预期的格式
      const sanitizedInput = input.replace(/<script>/gi, "&lt;script&gt;");
    
      return sanitizedInput;
    }
    
    const userInput = "<script>alert('XSS攻击')</script>";
    const sanitizedInput = sanitizeInput(userInput);
    
    // 在输出用户输入之前,确保进行了合理的验证和过滤
    console.log(sanitizedInput); // 输出: &lt;script&gt;alert('XSS攻击')&lt;/script&gt;
    
  • 在输出用户输入之前进行适当的转义,以确保不会被浏览器解释为代码。

    function escapeHTML(string) {
      const htmlEscapedChars = {
        "<": "&lt;",
        ">": "&gt;",
        "&": "&amp;",
        "'": "&#39;",
        "\"": "&quot;",
        "/": "&#x2F;"
      };
    
      return string.replace(/[<>&'"/]/g, (char) => htmlEscapedChars[char]);
    }
    
    const userInput = "<script>alert('XSS攻击')</script>";
    const escapedInput = escapeHTML(userInput);
    
    // 在输出用户输入之前,确保进行了适当的转义
    console.log(escapedInput); // 输出: &lt;script&gt;alert('XSS攻击')&lt;/script&gt;
    
  • 使用内容安全策略(CSP)配置来限制哪些资源可以加载,并阻止执行内联脚本。

    <!DOCTYPE html>
    <html>
    
    <head>
      <!-- 在 HTTP 头部或 HTML 中设置内容安全策略 -->
      <meta http-equiv="Content-Security-Policy" content="script-src 'self'">
    </head>
    
    <body>
      <!-- 内联脚本将不会被执行,符合 CSP 的限制 -->
      <script>alert('XSS攻击')</script>
    </body>
    
    </html>
    

请注意,这些示例只是简单演示,为了说明防御措施的原理,实际情况需要根据具体的应用和环境来采取适当的防御措施。

二、 CSRF(跨站请求伪造)

CSRF 是一种攻击技术,攻击者通过利用用户在目标网站中身份验证的信任,伪造一个请求并将其发送到该网站。当用户在目标网站中进行身份验证时,攻击者的恶意请求会被执行。

1. CSRF 的特点

在用户不知情的前提下利用用户权限(cookie)构造指定HTTP请求,窃取或修改用户敏感信息。

image.png

2. 防御 CSRF 攻击

防御 CSRF 攻击的关键是通过使用适当的验证机制来确保请求的来源是可信任的。以下是一些防御 CSRF 攻击的方法:

  • 使用POST请求

    由于伪造GET请求的难度相对较小(只需打开URL或请求资源),因此对于涉及关键业务操作的接口,尽量使用POST请求。这是因为POST请求通常需要更多的条件和数据,使攻击者更难以伪造有效的请求。

  • 增加验证码

    通过增加验证码等验证手段,只有通过验证的请求才被视为合法请求。此方法确保了请求的真实性,以防止被恶意伪造的请求成功执行。

  • 设置SameSite属性

    CSRF攻击的特点之一是,伪造请求的域名通常不是受攻击网站。通过设置Cookies的SameSite属性为Strict,仅允许同源网站发送带有Cookies的请求。这样可以阻止跨域攻击者在用户的浏览器中执行伪造的请求。需要注意的是,这种方法可能受到一些不兼容的浏览器版本的限制。

  • 验证Referer

    由于伪造请求通常不会包含正确的Referer信息,可以根据请求头中的Referer字段识别请求的来源是否可信。通过验证Referer,可以防止不受信任的请求进行伪造。然而,攻击者可能通过设置请求不携带Referer来绕过这种防御措施,因此这只能作为辅助的防御方法。

  • 验证CSRF令牌

    这是一种广泛应用的有效防御方法。服务器在每个会话中生成一个随机的CSRF令牌,并将其保存在会话中和客户端的 .Cookies 或 .表单字段 中。在发送请求时,客户端要么将令牌作为HTTP请求的头部,要么作为参数发送给服务器。服务器收到请求后,验证请求中的令牌是否与会话中的令牌匹配。只有当令牌匹配时,请求才被视为合法请求。这种方法通常适用于非分离式和分离式的项目。对于非分离式项目,令牌可以直接写入模板中的隐藏表单字段中,以实现发送请求时不需要额外的操作。而对于分离式项目,令牌可以在登录时写入Cookies中,在发送请求时,JavaScript从Cookies中读取令牌,并设置为HTTP请求的头部。

  • 更换登录态方案

    由于CSRF攻击本质上是利用受害者在浏览器中已经验证的会话,如果替换会话验证机制,例如使用JSON Web Token(JWT),其令牌信息通常存储在HTTP头部中,可以有效防止CSRF攻击。

    以下是基于 JWT 在防御 CSRF 攻击方面的一些关键优势:

    (1)CSRF Token 不再必需:传统的基于 Session 的方案通常需要使用 CSRF Token 来在表单或请求中进行验证,以阻止 CSRF 攻击。而在基于 JWT 的方案中,JWT 本身包含了验证信息,不需要额外的 CSRF Token,从而简化了实现和管理的复杂性。

    (2)阻止跨域请求:基于 JWT 的方案通常会将 JWT 存储在请求的 Header 中,例如 Authorization Header,而跨域请求通常无法携带自定义 Header。这样,攻击者无法在跨域请求中发送有效的 JWT,从而有效地阻止 CSRF 攻击。

    (3)验证令牌完整性:在传统的基于 Session 的方案中,服务器需要从会话存储中获取与请求关联的 Session ID,并进行验证。而在基于 JWT 的方案中,服务器只需要验证 JWT 的签名和有效期,确保 JWT 的完整性和合法性。

    需要注意的是,尽管基于 JWT 的方案提供了一些优势来防御 CSRF 攻击,本文只是基于 防御 CSRF 攻击来阐述了 JWT 的优势,但最终选择合适的登录态方案是根据应用需求、安全性要求和技术架构来决定的。无论选择基于 Session 还是基于 JWT 的方案,都需要遵循相关的安全最佳实践,以确保登录态的安全性和应用的整体安全性。

碎碎念

希望本文能增加大家对 XSS 和 CSRF 的认识。但安全性是一个持续的过程,需要不断学习和更新防御措施以应对新的安全威胁。因为我也是因为青训营课程刚接触web开发安全这方面的知识,没法很细致的讲,如果发现问题或者需要补充的点欢迎大家通过评论告诉我!!!