我在一些MVC应用程序中看到使用令牌密钥来防止CSRF。可以使用它的典型示例是post的删除方法。
我已经看到使用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
根据文档,添加安全组件会自动将表单键添加到使用表单助手的所有表单。
e.g。
public $components = array(
'Security' => array(
'csrfExpires' => '+1 hour'
)
);
但是我有一些问题:
1。)为什么在删除等某些操作上使用POST而不是GET?由于控制器中的请求将检查用户是否经过身份验证,是否具有权限,以及是否具有正确的表单密钥。
2.。)如何在CakePHP中将安全组件与GET请求一起使用?假设我也需要处理路由。
答案 0 :(得分: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));
以上内容将使用核心配置文件中的salt密钥设置,但您也可以使用自定义salt替换true。
答案 1 :(得分:2)
对于第一个问题:
原因可能在于HTTP方法的定义。 GET
被定义为安全方法之一,这意味着它不能用于更改服务器的状态,而只能用于检索信息。您可以在this link上阅读有关HTTP方法的更多信息。由于HTML表单无法发送HTTP DELETE
请求,因此“解决方法”是使用某些可用方法,如果排除GET
作为“安全方法”,则会离开{{1} }。当然,您可以使用POST
来删除内容,但很多人会这样做,但GET
请求按惯例会发生,不会改变任何内容。
编辑如果您想了解有关HTTP方法和浏览器/ HTML支持的更多信息,请查看this SO question
答案 2 :(得分:1)
johhniedoe向我指出了Croogo 1.3的一个例子,说明他们是如何做出类似于我在问题中提出的问题。因为1.3在2.x之前是针对CakePHP的,所以代码有点过时了,所以我修改了如下:
首先使用作为名为token
的参数传递的安全组件使用的CSRF令牌创建链接(在本例中为删除链接)。
<?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回调函数__blackhole
,我在AppController中定义它以显示错误。
最后要注意的是,您必须允许令牌多次使用并持续例如一小时,这是因为否则令牌将被重置并且在发送GET请求后不再匹配
public $components = array(
'Security' => array(
'csrfExpires' => '+1 hour',
'csrfUseOnce' => false
)
);
答案 3 :(得分:0)
看到这个
如果启用了安全组件并且对所有表单使用FormHelper方法,则不必担心这一点。您也不必配置任何东西。它开箱即用。
对于CSRF,您可以使用以下选项:
property SecurityComponent::$csrfCheck
Whether to use CSRF protected forms. Set to false to disable CSRF protection on forms.
property SecurityComponent::$csrfExpires
The duration from when a CSRF token is created that it will expire on. Each form/page request will generate a new token that can only be submitted once unless it expires. Can be any value compatible with strtotime(). The default is +30 minutes.
property SecurityComponent::$csrfUseOnce
控制是否使用和燃烧CSRF令牌。设置为false以不在每个请求上生成新令牌。一个令牌将被重用,直到它过期。这降低了用户因令牌消耗而获得无效请求的机会。它具有使CSRF不太安全的副作用,因为令牌是可重用的。
如果你打开了所有内容,你应该在表单的html中看到CSRF令牌。您可以设置任何您喜欢的附加选项,但它几乎可以为您开箱即用。