什么是CSRF令牌?它的重要性是什么?它是如何工作的?

Sha*_*awn 572 csrf

好吧,伙计们,我正在编写一个Django应用程序,我只是想知道实际上csrf令牌是什么以及它如何保护数据.如果不使用csrf令牌,帖子数据是不安全的?

我知道如何使用csrf_token但我只需要一些信息它是如何工作的.

Lut*_*elt 1409

跨站请求伪造(CSRF)用简单的话说

  • 假设您目前正在登录您的网上银行 www.mybank.com
  • 假设汇款mybank.com将导致(概念上)表格的请求http://www.mybank.com/transfer?to=<SomeAccountnumber>;amount=<SomeAmount>.(不需要您的帐号,因为您的登录信息暗示了这一点.)
  • 您访问时www.cute-cat-pictures.org,不知道它是恶意网站.
  • 如果该网站的所有者知道上述请求的形式(简单!)并且正确猜测您已登录mybank.com(需要一些运气!),他们可以在其页面上包含一个请求http://www.mybank.com/transfer?to=123456;amount=10000(其中123456包含其开曼群岛帐户的编号)并且10000是您之前认为您很乐意拥有的金额).
  • 检索到该www.cute-cat-pictures.org页面,因此您的浏览器将发出该请求.
  • 您的银行无法识别此请求的来源:您的网络浏览器会将您的请求与您的www.mybank.comCookie 一起发送,这看起来非常合法.有你的钱!

这是没有CSRF令牌的世界.

现在好了一个 CSRF令牌:

  • 转移请求扩展为第三个参数:http://www.mybank.com/transfer?to=123456;amount=10000;token=31415926535897932384626433832795028841971.
  • 该令牌是一个巨大的,不可能猜到的随机数,mybank.com当他们为您提供时,它将包含在他们自己的网页上.这是不同的每个他们所服务的任何页面,任何人的时间.
  • 攻击者无法猜测令牌,无法说服您的网络浏览器放弃它(如果浏览器正常工作......),因此攻击者将无法创建有效请求,因为请求具有错误的令牌(或没有令牌)将被拒绝www.mybank.com.

结果:您保留10000货币单位.我建议你把一些捐赠给维基百科.

(你的旅费可能会改变.)

来自评论的编辑值得一读:

值得注意的是www.cute-cat-pictures.org,www.mybank.com由于HTTP访问控制,脚本通常无法访问您的反CSRF令牌.对于一些不合理地Access-Control-Allow-Origin: *为每个网站响应发送标题而不知道它是什么的人来说,这个注释很重要,因为他们无法使用其他网站的API.

  • 值得注意的是,由于HTTP访问控制,来自"www.cute-cat-pictures.org"的脚本通常无法访问来自www.mybank.com的反CSRF令牌.这个注释对于那些不合理地为每个网站响应发送标题"Access-Control-Allow-Origin:*"而不知道它是什么的人来说很重要,因为他们不能使用来自其他网站的API. (63认同)
  • 显然,令牌最好被命名为*anti*-CSRF令牌,但名称可能很复杂. (27认同)
  • @LutzPrechelt我认为令牌总是不同是不够的,它必须与会话配对,服务器必须检查它收到的令牌是否为服务器通过接收的cookie识别的会话生成.否则,黑客可以自己访问我的银行并获得一些有效的令牌.因此,如果您对每个表单使用新令牌,则必须将其与服务器上的sessionid配对.每个会话使用相同的令牌可能更容易. (11认同)
  • @AugustinRiedinger如果攻击者在他的计算机上打开网页 - 因为他们没有登录用户的cookie - 他们将不会收到相应的csrf令牌(每个csrf令牌应仅对特定用户会话有效).如果攻击者试图在用户的计算机上加载包含令牌的网页,并且脚本放在cute-cat-pictures网站上,浏览器将阻止他阅读www.mybank.com(和令牌),因为同源政策. (8认同)
  • @LutzPrechelt谢谢.为什么javascript无法从浏览器获取任何真实性令牌? (3认同)
  • 现代浏览器中的网页如何"猜测"您打开的其他标签,以及如何登录这些页面?通过javascript我认为这是不可能的.让我们假设所有网站都有严格的同源策略.CSRF攻击是否设定,您是否有易受攻击或受感染的浏览器和/或计算机? (3认同)
  • 什么阻止了`www.cute-cat-pictures.org`爬行`www.mybank.com`并在那里获得CSRF令牌?我的意思是,它只对登录后面的页面有用吗? (2认同)
  • @AugustinRiedinger:被抓取的页面将具有与打算转移金额的用户页面上提供的 CSRF 令牌不同的 CSRF 令牌。 (2认同)
  • @MitjaGustin猜测是这样的:“嗯,`mybank.com`是最大的银行,因此,每访问我的“可爱猫咪图片”的人中,每1万人中,就有约500个是“ mybank”客户-如果我很幸运,其中有5个将在那时登录“ mybank”。让我们看看...” (2认同)

Dmi*_*nko 219

是的,帖子数据是安全的.但该数据的起源并非如此.这样,有人可以欺骗用户使用JS登录到您的站点,同时浏览攻击者的网页.

为了防止这种情况,django将在cookie和表单数据中发送随机密钥.然后,当用户POST时,它将检查两个键是否相同.如果用户被欺骗,第三方网站无法获取您网站的cookie,从而导致身份验证错误.

  • 好吧,假设我在Facebook.com中注入"http://bank.com/transfer?from=x&to=y"的恶意iframe.如果您是bank.com的客户并且您访问Facebook,那么iframe将加载银行页面,并使用您的Cookie(因为浏览器会将它们发送到已知域名)并进行汇款.你什么都不知道. (5认同)
  • 改变推荐人很容易,我不会说它是一个可靠的信息.但是,CSRF令牌是使用服务器密钥生成的,通常与用户绑定 (4认同)

tko*_*one 72

该网站在制作表单页面时会生成唯一标记.将令牌/数据发回/返回服务器需要此令牌.

由于令牌是由您的网站生成的,并且仅在生成带有表单的页面时提供,因此其他一些网站无法模仿您的表单 - 他们将不会拥有令牌,因此无法发布到您的网站.

  • 用户是否可以获取源中的令牌输出,获取发送给他们的cookie,然后从第三方站点提交? (9认同)
  • @JackMarchetti是的.但是由于每次要从第三方网站提交表单时,您都必须加载页面并解析令牌,因此成本很高.如果你担心这种攻击方式,CSRF令牌应该理想地与其他形式的安全性相结合 (9认同)
  • @PaulPreibisch它应该在每个页面加载时更改 - 而不是每次登录.这样,攻击者每次想要提交表单时都必须请求页面.使其变得更加困难. (7认同)
  • @tkone,它并没有真正让它变得更加困难.如果只是努力和时间的两倍.它不会添加任何禁止处理.诀窍还在于将CSRF令牌与特定于域的cookie相关联,并将此cookie与表单一起发送.cookie和表单发布数据都必须在POST请求中发送到服务器.这种方式需要Cookie劫持攻击才能模拟合法请求. (7认同)
  • 我和@JackMarchetti有同样的问题,有什么不清楚 - 如果每次登录时CSRF令牌都有变化.如果它保持不变,那么什么会阻止攻击者首次登录,抓取请求令牌,然后在攻击中插入该令牌? (3认同)

小智 38

让我给你举个例子…

想象一下,你有一个像简化的Twitter这样的网站,在a.com上托管.签名用户可以将一些文本(推文)输入到作为POST请求发送到服务器的表单中,并在他们点击提交按钮时发布.在服务器上,用户由包含其唯一会话ID的cookie标识,因此您的服务器知道谁发布了推文.

表格可以简单:

 <form action="http://a.com/tweet" method="POST">
   <input type="text" name="tweet">
   <input type="submit">
 </form> 
Run Code Online (Sandbox Code Playgroud)

现在想象一下,一个坏人将这个表格复制并粘贴到他的恶意网站上,比如说b.com.表格仍然有效.只要用户登录到您的Twitter(即他们为a.com提供了有效的会话cookie),POST请求就会发送到http://a.com/tweet并在用户照常处理单击提交按钮.

到目前为止,只要用户了解表单的确切功能,这不是一个大问题,但如果我们的坏人调整这样的表单怎么办:

 <form action="https://example.com/tweet" method="POST">
   <input type="hidden" name="tweet" value="Buy great products at http://b.com/#iambad">
   <input type="submit" value="Click to win!">
 </form> 
Run Code Online (Sandbox Code Playgroud)

现在,如果你的一个用户最终进入坏人的网站并点击"点击赢取!"按钮,表单将提交到您的网站,用户可以通过cookie中的会话ID正确识别,隐藏的推文获取出版.

如果我们的坏人更糟糕,他会让无辜的用户在使用JavaScript打开他的网页时立即提交此表单,甚至可能完全隐藏在一个看不见的iframe中.这基本上是跨站点请求伪造.

可以轻松地从任何地方向任何地方提交表单.通常这是一个常见的功能,但是在更多情况下,仅允许从其所属的域提交表单非常重要.

如果您的Web应用程序不区分POST和GET请求(例如在PHP中使用$ _REQUEST而不是$ _POST),情况会更糟.不要那样做!数据更改请求可以像http://a.com/tweet?tweet=This+is+really+bad一样简单,嵌入恶意网站甚至是电子邮件.

如何确保表格只能从我自己的网站提交?这是CSRF令牌的用武之地.CSRF令牌是一个随机的,难以猜测的字符串.在具有要保护的表单的页面上,服务器将生成随机字符串,CSRF令牌,将其作为隐藏字段添加到表单中,并通过将其存储在会话中或通过设置cookie以某种方式记住它包含价值.现在表单看起来像这样:

    <form action="https://example.com/tweet" method="POST">
      <input type="hidden" name="csrf-token" value="nc98P987bcpncYhoadjoiydc9ajDlcn">
      <input type="text" name="tweet">
      <input type="submit">
    </form> 
Run Code Online (Sandbox Code Playgroud)

当用户提交表单时,服务器只需将发布的字段csrf-token(名称无关紧要)的值与服务器记住的CSRF令牌进行比较.如果两个字符串相等,则服务器可以继续处理该表单.否则,服务器应立即停止处理表单并响应错误.

为什么这样做?以上示例中的坏人无法获取CSRF令牌的原因有以下几种:

将静态源代码从我们的页面复制到另一个网站将是无用​​的,因为隐藏字段的值随每个用户而变化.如果没有坏人的网站知道当前用户的CSRF令牌,您的服务器将始终拒绝POST请求.

因为坏人的恶意页面是由用户的浏览器从不同的域(b.com而不是a.com)加载的,所以坏人没有机会编写JavaScript,加载内容,因此加载我们用户的当前CSRF令牌你的网页.这是因为Web浏览器默认情况下不允许跨域AJAX请求.

坏人也无法访问您的服务器设置的cookie,因为域名不匹配.

我什么时候应该防止跨站点请求伪造?如果您可以确保不混淆GET,POST和其他请求方法,如上所述,一个好的开始是默认保护所有POST请求.

您不必保护PUT和DELETE请求,因为如上所述,浏览器无法使用这些方法提交标准HTML表单.

另一方面,JavaScript确实可以发出其他类型的请求,例如使用jQuery的$ .ajax()函数,但请记住,对于AJAX请求,域必须匹配(只要您没有明确配置您的Web服务器) .

这意味着,即使它们是POST请求,您甚至不必向AJAX请求添加CSRF令牌,但是如果POST请求实际上是一个,您必须确保只绕过Web应用程序中的CSRF检查AJAX请求.你可以通过寻找像X-Requested-With这样的头文件来实现这一点,这些头文件通常包括AJAX请求.您还可以设置另一个自定义标头并检查它在服务器端的存在.这是安全的,因为浏览器不会向常规HTML表单提交添加自定义标头(见上文),因此Bad Guy先生没有机会用表单模拟此行为.

如果您对AJAX请求有疑问,因为由于某种原因您无法检查X-Requested-With之类的标头,只需将生成的CSRF标记传递给JavaScript并将标记添加到AJAX请求中.有几种方法可以做到这一点; 或者像常规HTML表单一样将其添加到有效负载中,或者向AJAX请求添加自定义标头.只要您的服务器知道在传入请求中查找它的位置,并且能够将其与会话或cookie中记住的原始值进行比较,您就会进行排序.

  • @Dan 为什么 b.com 可以访问另一个网站 a.com 的 cookie? (4认同)

gla*_*xly 5

它的根本是确保请求来自站点的实际用户.为表单生成csrf令牌,并且必须绑定到用户的会话.它用于向服务器发送请求,令牌在其中验证它们.这是防止csrf的一种方法,另一种方法是检查引用者头.

  • 不要依赖引用标题,它很容易被伪造. (7认同)
  • 这是正确的答案!令牌必须绑定到服务器上的会话.比较Cookie + Form数据,如最高投票的答案表明完全错误.这些组件都构成了客户端构造的请求的一部分. (3认同)
  • 实际上,没有.令牌必须绑定到服务器的每个REQUEST.如果您只将其绑定到会话,则可能会冒某人窃取会话令牌并使用该令牌提交请求的风险.因此,为了最大限度地提高安全性,必须将令牌绑定到每个http请求. (2认同)