运行 Laravel 5 攻城测试

Run siege tests on Laravel 5

所以我有一个 laravel 5 项目,我想对我使用围攻工具的测试服务器进行基准测试。

很遗憾,我发现您无法登录,因为 CSRF 通常是从提交表单中收到的。围攻中没有表格,无法发送此令牌。

我认为可以通过几种方式解决此问题,但我正在寻找可以保留在源代码管理中且不会对安全性产生负面影响的内容。什么是让围攻与 Laravel 一起工作而无需大量维护或只是懒惰和禁用 CSRF 的好方法?

两件事:

  1. 您可以设置围攻以登录您的网站。有关详细信息,请参阅 this ServerFault post,但这只会测试您的登录表单。
  2. 您可以使用相同的方法,在任何请求中发送 _token 参数

显然,这方面的文档是在代码的注释中找到的,而不是在官方手册中。

剩下的问题是用 _token 变量传递什么值。显然,虚假值正是 CSRF 应该防止的事情。我认为最简单的方法是修改 app/Http/Middleware/VerifyCsrfToken.php 以添加一个特殊条件,该条件将 "match" 反对预设值。

我要做的第一件事是在我的 .env 文件中创建一个包含我的人脸 CSRF 令牌的变量,例如

FAKE_CSRF_TOKEN=dd0dda7d4b5e92fafd9e5bebfabd7709

然后在 App\Http\Middleware\VerifyCsrfToken(即我上面提到的文件)中,您将覆盖 tokensMatch($request) 函数。你可以这样做:

protected function tokensMatch($request)
{
    $parent = parent::tokensMatch($request);
    $token = $request->input('_token');
    return $parent || $token == env('FAKE_CSRF_TOKEN');
}

然后在您的测试中,始终将您的假 CSRF 令牌值作为 _token 传递。当然,

This code should never be run on a production server!

如果是我,我可能会创建一个特殊的 .env.siege 文件并在我的测试或暂存服务器上设置 APP_ENV=siege。然后我会重写上面的 tokensMatch() 函数来做这样的事情:

protected function tokensMatch($request)
{
    $parent = parent::tokensMatch($request);
    if ('siege' === env('APP_ENV')) {
        $token = $request->input('_token');
        return $parent || $token == env('FAKE_CSRF_TOKEN');
    }
    return $parent;
}

这样一来,即使这个经过修改的中间件以某种方式进入了您的生产服务器,您也会有一些额外的保护措施来防止虚假的 CSRF 攻击。最终结果是您将能够几乎完全像在生产环境中一样对您的服务器进行压力测试,而无需禁用 CSRF。

话虽这么说,但我不知道 CSRF 检查在实践中到底有多耗费资源。关闭 CSRF 以进行压力测试可能更简单,而不是进行我在此处建议的更改。

所以上面的答案已经差不多了,但是有以下缺陷:

  • 它需要自己的配置类型。不行;我们只是希望生产能够免疫。其他任何东西都应该进行压力测试。
  • 它不包括 FAKE_CSRF_TOKEN 未被草率的开发人员定义
  • 必须能够提交到主树! Git是一种常见的部署机制,尽量少在VCS之外

所以我这样定义函数:

protected function tokensMatch($request)
{
    $parent = parent::tokensMatch($request);

    //if it isn't an actual token match, and we aren't on production
    if (! $parent && 'production' !== env('APP_ENV')) {
        //then get the token
        $token = $request->input('_token');
        $fake = env('FAKE_CSRF_TOKEN');

        //and test it versus our fake
        //it must actually be defined to work (no blanks)
        //generate an actual random string for security!
        if(strlen($fake) && $token === $fake)
            return true;
    }

    //otherwise, just return what we normally would
    return $parent;
}