分析Laravel框架的表单方法伪造

HTML 表单不支持 PUTPATCHDELETE 行为。但是我们在使用Laravel框架的时候,仍然可以定义一个仅支持PUT的路由:

Route::put(‘update‘, function (\Illuminate\Http\Request $request) {
    dd($_SERVER[‘REQUEST_METHOD‘], $request->getMethod());
});

只需要在html的表单中加入:

<form action="/update" method="POST">
    <input type="hidden" name="_method" value="PUT">
    <input type="hidden" name="_token" value="{{ csrf_token() }}">
</form>

使用起来是挺简单的,但你是否注意到,Laravel的表单方法伪造只有在form表单的method="POST"才会生效,这是为什么?带着这个小问题,我们来看看框架是怎么实现伪造的。

阅读源码

Laravel的路由匹配http请求时,是调用RequestgetMethod()方法获取method属性值,再根据这个属性值进行匹配然后分发路由的。

我们追踪\Illuminate\Http\Request类的getMethod方法,发现是继承自\Symfony\Component\HttpFoundation,源码如下:

    public function getMethod()
    {
      	// 追踪了method这个属性,发现除了在这个方法内,其他地方都是把这个属性设置为null,所以第一次调用getMethod方法时,$this->method必定为null。
        if (null !== $this->method) {
            return $this->method;
        }
				
      	// $_SERVER[‘REQUEST_METHOD‘]为HTTP的请求方式
        $this->method = strtoupper($this->server->get(‘REQUEST_METHOD‘, ‘GET‘));

      	// 只有POST请求,才可以进行表单方法伪造。
        if (‘POST‘ !== $this->method) {
            return $this->method;
        }

        $method = $this->headers->get(‘X-HTTP-METHOD-OVERRIDE‘);

      	// 关于self::$httpMethodParameterOverride这个属性,Laravel框架在启动之前,便把它设置会true了,所以进入这个条件分支
        if (!$method && self::$httpMethodParameterOverride) {
          // 这一句代码的意思优先拿$_POST中的_method字段,若不存在则去拿$_GET中的_method字段。
            $method = $this->request->get(‘_method‘, $this->query->get(‘_method‘, ‘POST‘));
        }

      	// 伪造的请求方式必须是字符串
        if (!\is_string($method)) {
            return $this->method;
        }

        $method = strtoupper($method);

        // 必须是合法的请求方式
        if (\in_array($method, [‘GET‘, ‘HEAD‘, ‘POST‘, ‘PUT‘, ‘DELETE‘, ‘CONNECT‘, ‘OPTIONS‘, ‘PATCH‘, ‘PURGE‘, ‘TRACE‘], true)) {
            return $this->method = $method;
        }

        if (!preg_match(‘/^[A-Z]++$/D‘, $method)) {
            throw new SuspiciousOperationException(sprintf(‘Invalid method override "%s".‘, $method));
        }

        return $this->method = $method;
    }

阅读这段代码,我们就可以知道,Laravel的表单方法伪造只不过是修改 \Illuminate\Http\Request类的method属性值,并不会改变http的真实请求方式。

到这里,关于Laravel的表单方法伪造只有在form表单的method="POST"才会生效这个问题,我们可以轻易的解释了:这一切只不过是框架与HTML表单之间的一个约定,定义了表单方法伪造的方式。

分析Laravel框架的表单方法伪造

上一篇:函数柯里化


下一篇:Vue中的Class Component使用指南