Understanding CSRF理解CSRF(跨域请求伪造)

The Express team's csrf and csurf modules frequently have issues popping up concerned about our usage of cryptographic functions. Express团队的csrfcsurf模块经常会出现一些问题,这些问题与我们对加密函数的使用有关。These concerns are unwarranted due to a misunderstanding of how CSRF tokens work. 由于对CSRF令牌如何工作的误解,这些担忧是没有根据的。So here's a quick run down!所以这里有一个快速运行!

Read this and still have questions? Want to tell us we're wrong? Open an issue!读了这篇文章,还有问题吗?想告诉我们我们错了吗?打开一个问题!

How does a CSRF attack work?跨域请求伪造攻击是如何起作用的?

On their own (phishing site), an attacker could create an AJAX button or form that creates a request against your site:攻击者可以在自己的网站(仿冒网站)上创建一个AJAX按钮或表单,以创建针对您网站的请求:

<form action="https://my.site.com/me/something-destructive" method="POST">
  <button type="submit">Click here for free money!</button>
</form>

This is worse with AJAX as the attacker could use other methods like DELETE as well as read the result. AJAX的情况更糟,因为攻击者可以使用其他方法,如DELETE和读取结果。This is particularly important when the user has some sort of session with very personal details on your site. 当用户在您的站点上有一些带有非常个人详细信息的会话时,这一点尤为重要。If this is in the context of a technologically illiterate user, there might be some inputs for credit card and social security info.如果这是在一个不懂技术的用户的情况下,可能会有一些信用卡和社会安全信息的输入。

How to mitigate CSRF attacks?如何减轻CSRF攻击?

Use only JSON APIs仅使用JSON API

AJAX calls use JavaScript and are CORS-restricted. AJAX调用使用JavaScript,并且受CORS限制。There is no way for a simple <form> to send JSON, so by accepting only JSON, you eliminate the possibility of the above form.简单的<form>要发送JSON,只接受JSON,就消除了上述形式的可能性。

Disable CORS禁用CORS

The first way to mitigate CSRF attacks is to disable cross-origin requests. 缓解CSRF攻击的第一种方法是禁用跨源请求。If you're going to allow CORS, only allow it on OPTIONS, HEAD, GET as they are not supposed to have side-effects.如果你要允许CORS,只允许它在OPTIONS, HEAD, GET,因为他们不应该有副作用。

Unfortunately, this does not block the above request as it does not use JavaScript (so CORS is not applicable).不幸的是,这不会阻止上述请求,因为它不使用JavaScript(因此CORS不适用)。

Check the referrer header检查referrer标头

Unfortunately, checking the referrer header is a pain in the ass, but you could always block requests whose referrer headers are not from your site. 不幸的是,检查referer标头是一件麻烦事,但是你总是可以阻止那些referer头不是来自你的站点的请求。This really isn't worth the trouble.这真的不值得费心。

For example, you could not load sessions if the referrer header is not your server.例如,如果referer头不是您的服务器,则无法加载会话。

GET should not have side effectsGET不应该有副作用

Make sure that none of your GET requests change any relevant data in your database. 确保GET请求不会更改数据库中的任何相关数据。This is a very novice mistake to make and makes your app susceptible to more than just CSRF attacks.这是一个非常新手犯的错误,使您的应用程序容易受到CSRF攻击。

Avoid using POST避免使用POST

Because <form>s can only GET and POST, by using other methods like PUT, PATCH, and DELETE, an attacker has fewer methods to attack your site.因为<form>只有GETPOST,通过使用其他方法(如PUTPATCHDELETE),攻击者可以使用较少的方法攻击您的站点。

Don't use method override!不要使用方法重写!

Many applications use method-override to use PUT, PATCH, and DELETE requests over a regular form. This, however, converts requests that were previously invulnerable vulnerable!许多应用程序使用方法重写在常规表单上使用PUTPATCHDELETE请求。但是,这会转换以前不受攻击的请求!

Don't use method-override in your apps - just use AJAX!

Don't support old browsers不支持旧浏览器

Old browsers do not support CORS or security policies. 旧浏览器不支持CORS或安全策略。By disabling support for older browsers (which more technologically-illiterate people use, who are more (easily) attacked), you minimize CSRF attack vectors.通过禁用对旧浏览器的支持(更不懂技术的人使用旧浏览器,他们更容易受到攻击),可以最小化CSRF攻击向量。

CSRF Tokens

Alas, the final solution is using CSRF tokens. How do CSRF tokens work?唉,最终的解决方案是使用CSRF令牌。CSRF代币如何工作?

  1. Server sends the client a token.服务器向客户端发送令牌。
  2. Client submits a form with the token.客户端提交带有令牌的表单。
  3. The server rejects the request if the token is invalid.如果令牌无效,服务器将拒绝请求。

An attacker would have to somehow get the CSRF token from your site, and they would have to use JavaScript to do so. 攻击者必须以某种方式从您的站点获取CSRF令牌,并且必须使用JavaScript来实现这一点。Thus, if your site does not support CORS, then there's no way for the attacker to get the CSRF token, eliminating the threat.因此,如果您的站点不支持CORS,则攻击者无法获得CSRF令牌,从而消除威胁。

Make sure CSRF tokens can not be accessed with AJAX!确保不能使用AJAX访问CSRF令牌! Don't create a /csrf route just to grab a token, and especially don't support CORS on that route!不要仅仅为了获取令牌而创建/csrf路由,尤其不要在该路由上支持CORS!

The token just needs to be "unguessable", making it difficult for an attacker to successfully guess within a couple of tries. 令牌只需要是“不可用的”,使得攻击者很难在几次尝试中成功猜测。It does not have to be cryptographically secure. 它不必是加密安全的。An attack is one or two clicks by an unbeknownst user, not a brute force attack by a server.攻击是未知用户的一次或两次单击,而不是服务器的暴力攻击。

BREACH attack

This is where the salt comes along. The BREACH attack is pretty simple: if the server sends the same or very similar response over HTTPS+gzip multiple times, an attacker could guess the contents of response body (making HTTPS utterly useless). 这就是盐的来源。破坏攻击非常简单:如果服务器多次通过HTTPS+gzip发送相同或非常相似的响应,攻击者可能会猜到响应正文的内容(使HTTPS完全无用)。Solution? Make each response a tiny bit different.解决方案让每个反应都有一点点不同。

Thus, CSRF tokens are generated on a per-request basis and different every time. 因此,CSRF令牌是基于每个请求生成的,并且每次都不同。But the server needs to know that any token included with a request is valid. Thus:但是服务器需要知道请求中包含的任何令牌都是有效的。因此:

  1. Cryptographically secure CSRF tokens are now the CSRF "secret", (supposedly) only known by the server.加密安全的CSRF令牌现在被称为CSRF“秘密”(据说)只有服务器知道。
  2. CSRF tokens are now a hash of the secret and a salt.CSRF代币现在是秘密和盐的混合体。

Read more here:请在此处阅读更多信息:

Note that CSRF doesn't solve the BREACH attack, but the module simply randomizes requests to mitigate the BREACH attack for you.请注意,CSRF并不能解决漏洞攻击,但该模块只是将请求随机化,以减轻漏洞攻击。

The salt doesn't have to be cryptographically secure盐不需要加密安全

Because the client knows the salt!!!因为客户知道盐!!! The server will send <salt>;<token> and the client will return the same value to the server on a request. 服务器将发送<salt>;<token>,而客户端将根据请求向服务器返回相同的值。The server will then check to make sure <secret>+<salt>=<token>. 然后服务器将进行检查以确保<secret>+<salt>=<token>The salt must be sent with the token, otherwise the server can't verify the authenticity of the token.salt必须与令牌一起发送,否则服务器无法验证令牌的真实性。

This is the simplest cryptographic method. There are more methods, but they are more complex and not worth the trouble.这是最简单的加密方法。有更多的方法,但它们更复杂,不值得费心。

Creating tokens must be fast创建令牌必须快速

Because they are created on every request!因为它们是根据每个请求创建的! Doing something as simple as Math.random().toString(36).slice(2) is sufficient as well as extremely performant!做一些简单的事情,比如Math.random().toString(36).slice(2)就足够了,而且性能非常好! You don't need OpenSSL to create cryptographically secure tokens on every request.您不需要OpenSSL在每个请求上创建加密安全的令牌。

The secret doesn't have to be secret秘密不一定是秘密

But it is. If you're using a database-backed session store, the client will never know the secret as it's stored on your DB. 但事实确实如此。如果您使用的是数据库支持的会话存储,那么客户机将永远不会知道这个秘密,因为它存储在您的数据库中。If you're using cookie sessions, the secret will be stored as a cookie and sent to the client. 如果您正在使用cookie会话,则机密将存储为cookie并发送到客户端。Thus, make sure cookie sessions use httpOnly so the client can't read the secret via client-side JavaScript!因此,请确保cookie会话使用httpOnly,以便客户端无法通过客户端JavaScript读取机密!

When you're using CSRF tokens incorrectly当您错误地使用CSRF令牌时

Adding them to JSON AJAX calls将它们添加到JSON AJAX调用中

As noted above, if you don't support CORS and your APIs are strictly JSON, there is absolutely no point in adding CSRF tokens to your AJAX calls.如上所述,如果您不支持CORS,并且您的API严格使用JSON,那么将CSRF令牌添加到AJAX调用中是毫无意义的。

Exposing your CSRF token via AJAX通过AJAX公开您的CSRF令牌

Don't ever create a GET /csrf route in your app and especially don't enable CORS on it. 永远不要在应用程序中创建GET /csrf路由,尤其不要在其上启用CORS。Don't send CSRF tokens with API response bodies.不要发送带有API响应主体的CSRF令牌。

Conclusion结论

As the web moves towards JSON APIs and browsers become more secure with more security policies, CSRF is becoming less of a concern. 随着web向JSON API的发展,浏览器变得更加安全,有了更多的安全策略,CSRF就不再那么令人担忧了。Block older browsers from accessing your site and change as many of your APIs to be JSON APIs, and you basically no longer need CSRF tokens. 阻止旧浏览器访问您的站点,并将尽可能多的API更改为JSON API,您基本上不再需要CSRF令牌。But to be safe, you should still enable them whenever possible and especially when it's non-trivial to implement.但是为了安全起见,您仍然应该尽可能地启用它们,尤其是在实现起来非常困难的情况下。