为什么这个 Laravel CSRF 漏洞有效?

信息安全 php csrf 拉拉维尔
2021-08-13 18:19:04

最近Laravel 4进行了更新以解决一个安全问题:他们的代码中有一个 CSRF 漏洞

这是旧代码:

if (Session::token() != Input::get('_token'))
{
    throw new Illuminate\Session\TokenMismatchException;
}

这是他们的解决方法(注意!==):

if (Session::token() !== Input::get('_token'))
{
    throw new Illuminate\Session\TokenMismatchException;
}

==我了解 PHP和PHP之间的区别===(基本上后者更严格,因为它检查类型),并且我了解 CSRF 是什么以及如何解决它,但我不完全了解为什么这种特定情况会产生漏洞,或者如何攻击者会利用它。

2个回答

圣诞节在这里...

长话短说,DarkLighting 是非常正确的。

Input::get()通常从请求参数中读取,但如果请求是 JSON,那么它会从 JSON 正文中读取。JSON 允许您指定数据的类型,因此我发送了一个 int(0) 来代替 CSRF 令牌字符串,它将在大多数情况下通过松散的比较。

另一个技巧是,由于浏览器中的 CORS 检查,通常您不能跨站点发送 JSON 请求。但是,Laravel 的 JSON 检查很差,它基本上检查字符串'/json'是否在内容类型中的任何位置,如果存在,则通过 JSON 解析器运行整个请求并将其输入Input.

因此,您可以使用类似这样的方法来利用它(jquery 示例)

$.ajax("http://<laravel app>/sensitiveaction", {
    type: 'post',
    contentType: 'application/x-www-form-urlencoded; charset=UTF-8; /json',
    data: '{"sensitiveparam": "sensitive", "_token": 0}',
});

看起来这是一次私人披露,所以除非有人花时间分析框架代码(或@chrismsnz 决定向我们解释),否则我们似乎无法确定这一点。

但据我所知,似乎Session::token()返回一个字符串,而Input::get()返回一个混合对象。

通过他们给出的相当简短的解释,研究人员找到了一种使用JSON使变量包含任意数据的方法,但该值没有正确的类型(字符串)。由于框架只检查正确的值,他能够绕过过滤器。