security - 为什么将 CSRF 预防 token 放在 cookie 中很常见?

标签 security cookies web csrf owasp

我试图了解 CSRF 的整个问题以及防止它发生的适当方法。 (我已阅读、理解并同意的资源: OWASP CSRF Prevention CHeat SheetQuestions about CSRF 。)

据我了解,CSRF 的漏洞是由以下假设引入的:(从网络服务器的角度来看)传入 HTTP 请求中的有效 session cookie 反射(reflect)了经过身份验证的用户的愿望。但是原始域的所有 cookie 都被浏览器神奇地附加到请求中,因此实际上所有服务器都可以从请求中存在有效 session cookie 中推断出该请求来自具有经过身份验证的 session 的浏览器;它无法进一步假设有关在该浏览器中运行的代码的任何信息,或者它是否真的反射(reflect)了用户的意愿。防止这种情况的方法是在请求中包含额外的身份验证信息(“CSRF token ”),通过浏览器的自动 cookie 处理以外的其他方式携带。粗略地说, session cookie 对用户/浏览器进行身份验证,CSRF token 对浏览器中运行的代码进行身份验证。

所以简而言之,如果您使用 session cookie 来验证 Web 应用程序的用户,您还应该向每个响应添加一个 CSRF token ,并在每个(变异)请求中要求一个匹配的 CSRF token 。然后,CSRF token 从服务器到浏览器返回服务器,向服务器证明发出请求的页面已被该服务器批准(甚至由该服务器生成)。

关于我的问题,这是关于该往返中用于该 CSRF token 的特定传输方法。

似乎很常见(例如在 AngularJSDjangoRails 中)将 CSRF token 作为 cookie 从服务器发送到客户端(即在 Set-Cookie header 中),然后让客户端中的 Javascript 将其刮掉cookie 并将其附加为单独的 XSRF-TOKEN header 以发送回服务器。

(另一种方法是例如 Express 推荐的方法,其中服务器生成的 CSRF token 通过服务器端模板扩展包含在响应正文中,直接附加到将提供回服务器的代码/标记,例如作为一个隐藏的表单输入。这个例子是一种更像 web 1.0-ish 的做事方式,但可以很好地推广到更重 JS 的客户端。)

为什么使用 Set-Cookie 作为 CSRF token 的下游传输如此普遍/为什么这是个好主意?我想所有这些框架的作者都仔细考虑了他们的选择并且没有弄错。但乍一看,使用 cookie 来解决本质上对 cookie 的设计限制似乎很愚蠢。事实上,如果你使用 cookie 作为往返传输(Set-Cookie: header 下游的服务器告诉浏览器 CSRF token ,和 Cookie: header 上游的浏览器将其返回给服务器)你会重新引入你的漏洞正在尝试修复。

我意识到上面的框架没有在整个 CSRF token 的往返过程中使用 cookie;他们在下游使用 Set-Cookie,然后在上游使用其他东西(例如 X-CSRF-Token header ),这确实关闭了漏洞。但即使使用 Set-Cookie 作为下游传输也有潜在的误导性和危险性;浏览器现在会将 CSRF token 附加到每个请求,包括真正的恶意 XSRF 请求;充其量这会使请求比它需要的更大,最坏的情况是一些善意但被误导的服务器代码实际上可能会尝试使用它,这将非常糟糕。此外,由于 CSRF token 的实际预期接收者是客户端 Javascript,这意味着该 cookie 不能仅使用 http 来保护。因此,在 Set-Cookie header 中向下游发送 CSRF token 对我来说似乎不太理想。

最佳答案

一个很好的理由,你已经有点接触了,一旦收到 CSRF cookie,它就可以在客户端脚本中的整个应用程序中使用,用于常规表单和 AJAX POST。这在诸如 AngularJS 使用的 JavaScript 重应用程序中是有意义的(使用 AngularJS 并不要求应用程序将是单页面应用程序,因此当状态需要在 CSRF 值的不同页面请求之间流动时它会很有用通常无法在浏览器中持久化)。

考虑典型应用程序中的以下场景和流程,了解您描述的每种方法的一些优缺点。这些基于 Synchronizer Token Pattern .

请求正文方法

  • 用户成功登录。
  • 服务器发出身份验证 cookie。
  • 用户单击以导航到表单。
  • 如果尚未为此 session 生成,则服务器生成 CSRF token ,将其存储在用户 session 中并将其输出到隐藏字段。
  • 用户提交表单。
  • 服务器检查隐藏字段是否匹配 session 存储的 token 。

  • 优点:
  • 实现简单。
  • 与 AJAX 一起使用。
  • 适用于表单。
  • Cookie 实际上可以是 HTTP Only .

  • 缺点:
  • 所有表单都必须以 HTML 格式输出隐藏字段。
  • 任何 AJAX POST 也必须包含该值。
  • 页面必须事先知道它需要 CSRF token ,以便它可以将其包含在页面内容中,因此所有页面都必须在某处包含 token 值,这可能会使大型站点的实现变得耗时。

  • 自定义 HTTP header (下游)
  • 用户成功登录。
  • 服务器发出身份验证 cookie。
  • 用户单击以导航到表单。
  • 页面在浏览器中加载,然后发出 AJAX 请求以检索 CSRF token 。
  • 服务器生成 CSRF token (如果尚未为 session 生成),将其存储在用户 session 中并将其输出到
    标题。
  • 用户提交表单( token 通过隐藏字段发送)。
  • 服务器检查隐藏字段是否匹配 session 存储的 token 。

  • 优点:
  • 与 AJAX 一起使用。
  • Cookie 可以是 HTTP Only .

  • 缺点:
  • 如果没有 AJAX 请求来获取 header 值,则不起作用。
  • 所有表单都必须动态地将值添加到其 HTML 中。
  • 任何 AJAX POST 也必须包含该值。
  • 该页面必须首先发出 AJAX 请求以获取 CSRF token ,因此每次都意味着额外的往返。
  • 也可以简单地将 token 输出到可以保存额外请求的页面。

  • 自定义 HTTP header (上游)
  • 用户成功登录。
  • 服务器发出身份验证 cookie。
  • 用户单击以导航到表单。
  • 如果尚未为此 session 生成,服务器会生成 CSRF token ,将其存储在用户 session 中,并将其输出到页面内容中的某处。
  • 用户通过 AJAX 提交表单( token 通过 header 发送)。
  • 服务器检查自定义 header 是否匹配 session 存储的 token 。

  • 优点:
  • 与 AJAX 一起使用。
  • Cookie 可以是 HTTP Only .

  • 缺点:
  • 不适用于表格。
  • 所有 AJAX POST 都必须包含标题。

  • 自定义 HTTP header (上游和下游)
  • 用户成功登录。
  • 服务器发出身份验证 cookie。
  • 用户单击以导航到表单。
  • 页面在浏览器中加载,然后发出 AJAX 请求以检索 CSRF token 。
  • 服务器生成 CSRF token (如果尚未为 session 生成),将其存储在用户 session 中并将其输出到
    标题。
  • 用户通过 AJAX 提交表单( token 通过 header 发送)。
  • 服务器检查自定义 header 是否匹配 session 存储的 token 。

  • 优点:
  • 与 AJAX 一起使用。
  • Cookie 可以是 HTTP Only .

  • 缺点:
  • 不适用于表格。
  • 所有 AJAX POST 也必须包含该值。
  • 该页面必须首先发出 AJAX 请求以获取 CRSF token ,因此每次都意味着额外的往返。

  • 设置 Cookie
  • 用户成功登录。
  • 服务器发出身份验证 cookie。
  • 用户单击以导航到表单。
  • 服务器生成 CSRF token ,将其存储在用户 session 中并将其输出到 cookie。
  • 用户通过 AJAX 或 HTML 表单提交表单。
  • 服务器检查自定义 header (或隐藏表单字段)是否与 session 存储的 token 匹配。
  • Cookie 在浏览器中可用,用于额外的 AJAX 和表单请求,无需额外请求服务器来检索 CSRF token 。

  • 优点:
  • 实现简单。
  • 与 AJAX 一起使用。
  • 适用于表单。
  • 不一定需要 AJAX 请求来获取 cookie 值。任何 HTTP 请求都可以检索它,并且可以通过 JavaScript 将其附加到所有表单/AJAX 请求。
  • 一旦检索到 CSRF token ,因为它存储在 cookie 中,该值可以在没有额外请求的情况下重复使用。

  • 缺点:
  • 所有表单都必须动态地将值添加到其 HTML 中。
  • 任何 AJAX POST 也必须包含该值。
  • cookie 将针对每个请求(即不涉及 CSRF 过程的图像、CSS、JS 等的所有 GET)提交,增加请求大小。
  • Cookie 不能是 HTTP Only .

  • 因此 cookie 方法是相当动态的,它提供了一种简单的方法来检索 cookie 值(任何 HTTP 请求)并使用它(JS 可以自动将值添加到任何表单,它可以在 AJAX 请求中用作 header 或作为形式值)。一旦收到 session 的 CSRF token ,就无需重新生成它,因为使用 CSRF 漏洞的攻击者无法检索此 token 。如果恶意用户试图通过上述任何一种方法读取用户的 CSRF token ,那么这将被 Same Origin Policy 阻止。 .如果恶意用户尝试检索 CSRF token 服务器端(例如,通过 curl),则此 token 将不会与同一用户帐户相关联,因为请求中将缺少受害者的身份验证 session cookie(这将是攻击者的 -因此它不会将服务器端与受害者的 session 相关联)。

    以及 Synchronizer Token Pattern还有Double Submit Cookie CSRF 预防方法,当然是使用 cookie 来存储一种 CSRF token 。这更容易实现,因为它不需要 CSRF token 的任何服务器端状态。使用这种方法时,CSRF token 实际上可以是标准的身份验证 cookie,并且该值像往常一样通过 cookie 与请求一起提交,但该值也在隐藏字段或 header 中重复,攻击者无法将其复制为他们首先无法读取值。但是,建议选择另一个 cookie,而不是身份验证 cookie,以便可以通过标记为 HttpOnly 来保护身份验证 cookie。所以这是您使用基于 cookie 的方法发现 CSRF 预防的另一个常见原因。

    关于security - 为什么将 CSRF 预防 token 放在 cookie 中很常见?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20504846/

    相关文章:

    windows - 如何在 DLL 中查找特定指令的内存地址

    javascript - 从 Javascript 访问在服务器端创建的 Cookie

    asp.net - postman 没有使用cookie

    apache-spark - 如何在网站中嵌入 LIVE Colab Notebook?

    web - 提供网站托管的项目托管站点

    linux - 我被硬件黑客入侵/后门了吗?

    android - 是否可以修改 WiFi 帧(第 2 层 PDU)以包含新字段?

    javascript - 为什么我设置cookie时出现多个重复的条目?

    java - 如何使用java单击selenium中的按钮而无需名称或ID

    php - 如何调用位于 public_html 之外的 php 文件