1

我在一些 MVC 应用程序中看到使用 Token 密钥来防止 CSRF。可以使用它的典型示例是帖子的删除方法。

而且我已经看到了使用 GET 和 POST 方法的实现。

带有令牌的示例 GET 请求链接:

https://domain.com/posts/G7j/delete/EOwFwC4TIIydMVUHMXZZdkbUR0cluRSkFzecQy3m5pMTYVXRkcFIBWUZYLNUNSNgQKdnpTWu

还有一个带有令牌的 POST 请求示例:

<form action="/posts/G7j/delete" method="post">
    <input type="hidden" name="token" value="EOwFwC4TIIydMVUHMXZZdkbUR0cluRSkFzecQy3m5pMTYVXRkcFIBWUZYLNUNSNgQKdnpTWu" />
    <button type="submit">Delete</button>
</form>

我一直在考虑根据文档将其实现到我的 CakePHP 应用程序中:http: //book.cakephp.org/2.0/en/core-libraries/components/security-component.html

并且根据文档,添加安全组件会自动将表单密钥添加到使用表单助手的所有表单中。

例如

public $components = array(
    'Security' => array(
        'csrfExpires' => '+1 hour'
    )
);

但是我有一些问题:

1.) 为什么要使用 POST 而不是 GET 来执行某些操作,例如删除?由于控制器中的请求将检查用户是否已通过身份验证、是否具有权限以及是否具有正确的表单密钥。

2.) 如何在 CakePHP 中使用带有 GET 请求的安全组件?假设我还需要处理路由。

4

3 回答 3

3

首先,CakePHP 使用发布链接删除作为附加的安全级别,因为例如您的身份验证系统不是 100% 安全的,用户可以通过手动输入 URL 来访问删除方法 - 如果我进入并输入 /users/delete /10 ,我实际上可以删除您服务器上的用户,这是您可以想象的风险。

其次,GET 请求可以被缓存或添加书签,因此为这些链接添加书签的用户最终可能会导航到损坏的链接,这绝不是一件好事,敏感数据也会在 URL 中可见,例如,如果有人使用 GET 变量为登录页面添加书签完好无损 - 这可能会危及那里的安全。

最后,您可以使用以下代码轻松生成自己的令牌:

$string = Security::hash('string', 'sha1 or md5', true);
print $this->Html->link("Link to somewhere",array("controller"=>"users","action"=>"delete",$string));

以上将使用核心配置文件中的盐键设置,但您也可以将 true 替换为自定义盐。

于 2013-08-21T17:56:08.047 回答
2

对于第一个问题:

原因可能在于 HTTP 方法的定义。GET被定义为安全方法之一,这意味着它不能用于改变服务器的状态,而只能用于检索信息。您可以在此链接上阅读有关 HTTP 方法的更多信息。由于 HTML 表单无法发送 HTTPDELETE请求,因此“解决方法”是使用一些可用的方法,如果您将其排除GET为“安全方法”,它就会离开POST。你当然可以GET用来删除东西,很多人都会这样做,但GET按照惯例,请求不会改变任何东西。

编辑:如果您有兴趣阅读有关 HTTP 方法和浏览器/HTML 支持的更多信息,请查看此 SO 问题

于 2013-08-13T17:48:47.070 回答
1

johhniedoe 将我指向 Croogo 1.3 以了解他们如何完成与我在问题中提出的类似的事情。因为 1.3 在 2.x 之前是针对 CakePHP 的,所以代码有点过时,所以我修改如下:

首先使用安全组件使用的 CSRF 令牌创建链接(在本例中为删除链接),并将其作为名为token.

<?php echo $this->Html->link('Delete', array('action'=>'delete','token'=>$this->params['_Token']['key'])); ?>

接下来我创建了一个通配符路由连接来处理令牌(这通常不是必需的,但是因为我们没有使用 NAMED 令牌并且我想保持 URL 更清晰):

Router::connect('/:controller/:action/:token', 
        array('controller' => 'action'),
        array(
            'pass' => array('token')
        )
    );

然后最后在你的方法中处理它,如下所示:

public function delete(){

    if (!isset($this->params['token']) || ($this->params['token'] != $this->params['_Token']['key'])) {
        $this->Security->blackHoleCallback = '__blackhole';
    } else {
        // do delete
    }
}

这基本上表示如果令牌不匹配,则使用__blackhole我在 AppController 中定义的黑洞回调函数来显示错误。

最后要注意的一件事是,您必须允许令牌多次使用并且持续例如一个小时,这是因为否则令牌将被重置并且在发送 GET 请求后不再匹配。

public $components = array(
    'Security' => array(
        'csrfExpires' => '+1 hour',
        'csrfUseOnce' => false
    )
);
于 2013-08-27T13:00:45.583 回答