thecodingmachine/csrf-header-check-middleware

一个符合 PHP PSR-15 规范的中间件,用于检查 CSRF 攻击。

v2.0.0 2018-02-27 16:16 UTC

This package is auto-updated.

Last update: 2024-09-13 22:43:39 UTC


README

Latest Stable Version Total Downloads Latest Unstable Version License Scrutinizer Code Quality Build Status Coverage Status

CSRF 头部检查中间件

此包包含一个符合 PHP PSR-15 规范的中间件,用于检查 CSRF 攻击。

它实现了 OWASP 对防止跨站请求伪造的一般推荐的第一条(通过标准头部验证同一来源)

注意,OWASP 建议还使用 CSRF 令牌。这需要修改您的应用程序,并且此中间件不提供任何关于 CSRF 令牌生成的帮助。其他包(如 Slim-CSRF)可以帮助您进行 CSRF 令牌验证。

它在做什么?

CsrfHeaderCheckMiddleware 会检查所有 POST/PUT/DELETE 请求(实际上是所有非 GET/HEAD/OPTIONS 的请求)。它会验证请求的 "Origin" 是否为您的网站。

它是通过比较 "Origin"(或作为备选的 "Referrer" 头部)与您的网站域名来实现的。如果头部不匹配(或如果找不到头部),它将触发一个异常。

为什么它有效?

在 CSRF 攻击中,受害者(Alice)已登录您的应用程序。攻击者(Eve)向 Alice 发送了一个恶意网站链接。恶意网站包含一些执行您网站表单 POST 的 JavaScript 代码。由于 Alice 已登录您的网站,POST 操作成功,允许 Eve 代表 Alice 执行操作。

查询因此由 Alice 的计算机执行。我们可以预期 Alice 的浏览器会像“正常”浏览器一样表现。

正常浏览器 不允许 JavaScript 代码修改“Origin”或“Referer”头部

与其他解决方案相比如何?

在应对 CSRF 攻击时,最常用的解决方案是在每个表单中生成一个令牌,将其存储在会话中,并检查用户是否发送了该令牌。如果您正在寻找基于 PSR-7/PSR-15 的 CSRF 令牌中间件,请查看 Ocramius/PSR7Csrf

与基于令牌的实现的优势

检查 HTTP 头部可以在中间件中完成。与基于令牌的中间件相比,您必须修改应用程序以生成令牌并将令牌与任何表单一起发送。相比之下,检查头部不需要做任何工作,只需添加中间件即可。因此,部署非常快。

限制

  • 此中间件完全绕过了 GET 请求。如果您的应用程序在 GET 请求上修改状态,您将陷入困境。当然,状态修改应该仅发生在 POST 请求上(但请务必再次检查,确保修改状态的路由仅与 POST/DELETE/PUT 请求一起工作)。
  • 此中间件期望 "Origin" 或 "Referer" 头部被填充。这通常是真的,除非您处于一个有代理服务器修改请求的内部环境。例如,一些代理服务器已知会剥离头部以使请求匿名。
  • 将阻止 CORS 请求。如果您期望请求来自您的网站之外的来源,则不能使用此中间件。
  • 如果您的网站是通过第三方应用程序(如手机应用)访问的,您不能使用此中间件,因为来源和引用将会是空的。

如果您处于这些情况之一,请使用基于令牌的中间件。

安装

composer require thecodingmachine/csrf-header-check-middleware

使用

最简单的使用方法是基于默认设置。它假设您已经配置了一个兼容PSR-7的应用程序,该应用程序支持管道中间件。

zendframework/zend-expressive应用程序中,设置如下所示

$app = \Zend\Expressive\AppFactory::create();

$app->pipe(\TheCodingMachine\Middlewares\CsrfHeaderCheckMiddlewareFactory::createDefault();

猜测您的域名

此中间件会尽力“猜测”您网站的域名。为此,它将检查HTTP请求的“Host”头。

您需要知道这一点

  • 正常浏览器总是发送“Host”头(至少在HTTP 1.1中如此)。
  • 在正常浏览器中,“Host”头不能被JavaScript代码修改。

然而

  • “Host”头可以被代理修改
  • 代理通常会将在前一个“Host”头放入“X-Forwarded-Host”头中
  • “X-Forwarded-Host”头不可信,因为它可以从客户端(在JavaScript中)被修改

因此,如果您在代理后面运行应用程序,或者由于某些原因处理HTTP/1.0,您必须手动指定应用程序的域名。

// The first argument of the factory is a list of domain name for your application.
$app->pipe(\TheCodingMachine\Middlewares\CsrfHeaderCheckMiddlewareFactory::createDefault([
    'alice.com',
    'www.alice.com'
]);

禁用CSRF检查

您可以根据路由逐个禁用CSRF检查

// The second argument of the factory is a list of regular expressions that will be matched on the path.
// Here, we disable CSRF checks on /api/*
$app->pipe(\TheCodingMachine\Middlewares\CsrfHeaderCheckMiddlewareFactory::createDefault([], [
    '#^/api/#'
]);

这对于仅用于服务器之间通信的API可能很有用。请注意,如果您决定禁用某些路由的CSRF,您需要为此路由提供其他形式的保护。

或者,任何传递给中间件并设置了'TheCodingMachine\BypassCsrf'属性的请求将被忽略

// Put this in a middleware placed before the `CsrfHeaderCheckMiddleware` to disable it.
$request = $request->withAttribute('TheCodingMachine\\BypassCsrf', true);