laravel的csrf防御机制详解

2014.07.05

一、什么是CSRF

    CSRF是Cross Site Request Forgery的缩写,乍一看和XSS差不多的样子,但是其原理正好相反,XSS是利用合法用户获取其信息,而CSRF是伪造成合法用户发起请求。具体操作原理看google。

二、Laravel的CSRF防御过程

    Laravel框架会自动在用户 session 中存放一个随机令牌(token),并且将这个令牌作为一个隐藏字段包含在表单信息中。当然,你也可以使用表单的 token 方法直接调用令牌字段的HTML代码。

  1. 在视图页面中:
{{ Form::token() }}
  1. 任何地方可以这样获取:
csrf_token();

三、Token产生原理

通过 Illuminate\Session\Store 类的 getToken 方法获取随机产生长度为40的字符串,而这40个字符是由 Illuminate\Support\Str 类的 random 方法产生,但是这个方法有个地方总觉得不太合适。分析如下:

public static function random($length = 16)

{

    if (function_exists('openssl_random_pseudo_bytes'))

    {

        $bytes = openssl_random_pseudo_bytes($length * 2);

        if ($bytes === false)

        {

            throw new \RuntimeException('Unable to generate random string.');

        }

        return substr(str_replace(array('/', '+', '='), '', base64_encode($bytes)), 0, $length);

    }

    return static::quickRandom($length);

}

可以看到,这里的一个处理是这样的,如果 openssl_random_pseudo_bytes 这个方法获取随机数据失败的话(在PHP文档关于这个openssl_random_pseudo_bytes方法的介绍中提示在某些情况下可能执行失败,看来还是比较危险的),直接抛出异常了,这时候网站就报错了,各位同学会不会觉得他们这样做太粗鲁了?

我觉得合适的办法是在 openssl_random_pseudo_bytes 这个方法执行返回 false 的情况下继续执行,通过这个类的静态方法quickRandom获取,代码如下:

public static function random($length = 16)

{

    if (function_exists('openssl_random_pseudo_bytes'))

    {

        $bytes = openssl_random_pseudo_bytes($length * 2);

        if ($bytes !== false)

        {

            return substr(str_replace(array('/', '+', '='), '', base64_encode($bytes)), 0, $length);

        }

    }

    return static::quickRandom($length);

}
Comments
Write a Comment