CSRF(跨站请求伪造)攻击和预防

什么是 CSRF 漏洞?

当使用 cookie 进行会话管理的 Web 应用程序无法验证 HTTP POST 请求的来源时,通常会出现 CSRF(跨站点请求伪造)漏洞。

当 Web 应用程序通过使用 GET 方法进行更改而滥用 GET 方法时,也会发生这种情况。这两种情况都允许恶意网站代表登录用户执行不需要的操作。

如何防范 CSRF 漏洞?

按着这些次序。

  1. 使用您的应用程序平台/库提供的 CSRF 令牌。
  2. 请勿使用 POST、PUT、PATCH 或 DELETE 以外的其他 HTTP 动词进行更改。
  3. 使用“SameSite”指令保护您的 cookie。

同源政策

在开始之前,了解 SOP(Same Origin Policy)是很有帮助的,它是 Web 浏览器安全模型的核心和灵魂。这是一个或多或少说的规则:

  1. 如果两个 URL 的协议、端口(如果指定)和主机相同,则它们的来源相同。
  2. 任何来源的网站都可以自由地向任何其他GET来源发送、、、POST和请求。此外,该请求包括该来源的用户 cookie(包括会话 ID)。HEADOPTIONS
  3. 虽然可以发送请求,但来自一个来源的网站无法直接读取来自另一个来源的响应。
  4. 网站仍然可以从这些 HTTP 响应中消耗资源,例如通过执行脚本、使用字体/样式或显示图像。JSONP hack 利用了第四条规则(不要使用 JSONP)。
  5. 如果网站获得窗口句柄,则来自一个来源的网站可以限制访问另一个来源的窗口。最值得注意的是来自不同来源的窗口可以更改彼此的 URL ( anotherWindow.location.replace("https://www.evil.com")。

例如,这个网站的来源是在https://www.appsecmonkey.com/哪里,主机在哪里,并且没有指定端口(这是隐含的,因为协议)。protocolhttpswww.appsecmonkey.com443https

一个简单的例子

让我们假设用户可以像这样登录 AppSec Monkey 并更新他们的电子邮件地址:

POST /user/update-email/ HTTP/1.1
Host: www.appsecmonkey.com
Cookie: SessionId=ABC123
...

[email protected]

后端代码可能看起来像这样(至少如果你使用 Django):

def update_email(request):
  new_email = request.POST['new_email']
  set_new_email(request.user, new_email)

现在假设有一个evil.example.com带有以下 HTML 表单和自动提交脚本的邪恶网站:

当当前登录的用户www.appsecmonkey.com进入恶意网站时,将代表用户自动提交 HTML 表单,并立即将以下 HTTP POST 请求发送到www.appsecmonkey.com

POST /user/update-email/ HTTP/1.1
Host: www.appsecmonkey.com
Cookie: SessionId=ABC123
...

[email protected]

Bob 的电子邮件地址更改为[email protected].

CSRF 代币

防止这些攻击的常用方法是使用称为 CSRF 令牌的东西。它可以让您在 HTML 表单中添加一个隐藏的值,攻击者无法猜到。

当另一个网站喜欢evil.example.com尝试提交表单时,网络服务器会拒绝 POST 请求,因为它不包含用户的 CSRF 令牌。

所有现代 Web 应用程序框架(Spring、Express、Symfony、Django、ASP.Net MVC等)。物有所值有这样的 CSRF 保护机制,所以不要创建自己的.

这是你的第一道防线。

不要忘记登录端点

它也是一个漏洞,通常可以通过某种方式利用,如果恶意网站可以在不知不觉中使用他们的帐户登录您的用户。

为防止这种情况,请确保在登录表单中也使用 CSRF 令牌。

您应该将令牌绑定到预身份验证会话(当用户进行身份验证并为用户提供新的会话 ID 时,您应该将其丢弃,但这是另一回事)。

或者,如果您使用 OAuth/OIDC,请确保您state正确验证了参数(有关详细信息,请参见此处)。

在这两种情况下,现代应用程序框架都应该能够毫不费力地处理它。

注意你的 HTTP 动词

CSRF-token 机制倾向于只保护 POST 请求。因此,如果您接受 GET 请求,例如https://www.appsecmonkey.com/user/[email protected],无论您可能使用任何 CSRF 保护,您通常都容易受到攻击。

确保您不使用除 POST/PUT/PATCH/DELETE 之外的任何东西进行更改。

现代平台倾向于明确动词,但有时您必须小心遗留框架。

使用 SameSite cookie

现在的浏览器支持一个很酷的特性,叫做SameSite cookie。当您使用 设置 cookie 时SameSite=Lax,浏览器不会将其包含在跨站点 POST 请求中。

Set-Cookie: SessionId=123; ...other options... SameSite=Lax

就是这样,简单而有效。但是不要仅仅依靠这个特性来保证你的应用程序的安全。使用 CSRF 令牌作为您的主要防御,并应用 SameSite cookie 作为额外的保护层。

您还可以在SameSite=Strict模式下设置 cookie。在这种情况下,GET 请求也将受到保护。但是,如果您遵循上述注意 HTTP 动词的规则,这对于 CSRF 保护来说不是必需的。而且它会在某种程度上破坏功能,因为指向应用程序的链接将不再按预期工作(在打开选项卡/窗口时将不再登录用户)。

使用该Strict变体的好处是可以防止某些 XSS(跨站点脚本)攻击,因此您可能至少要考虑一下。

使用无 cookie 会话管理

CSRF 是一个影响使用 cookie 进行会话管理的应用程序的漏洞。避免它们的一种方法是使用其他东西,例如 JavaScript 会话令牌。但这种方法也有缺点。例如,XSS 攻击可以访问令牌。相比之下,Web 应用程序可以使用该HttpOnly属性保护 cookie 免受 JavaScript 代码的影响。

结论

CSRF 攻击可能很危险。幸运的是,只要您使用支持 CSRF 令牌并明确 HTTP 动词的体面、现代的应用程序平台,它们也很容易避免。SameSite cookie 为您的应用程序提供了出色的附加安全层,但不应仅依赖于安全性。

你可能感兴趣的:(csrf,前端)