Symfony2 通过表单处理 PUT cross-domain 请求
Symfony2 processing PUT cross-domain request via forms
我有两个独立的项目:UI(AngularJS) 和 Server(Symfony2)。
我需要从 AngularJS 应用程序发送 cross-domain PUT 请求到 Symfony2 应用程序。
在 Symfony 控制器中,我将 $request
传递给 form->handleRequest();
并且调试显示我没有提交使用这种方式的表单。
因此,接下来我尝试将 $request
传递给 form->submit()
并得到错误 "Invalid CSRF Token"。
- 如何通过 Symfony 表单正确处理 cross-domain 数据?
我读过将
$request
传递给 submit() 方法是
被贬低了。
- 如果我从 UI 通过
headers ? (我在请求中添加了 csrf 字段,但它没有在 back-end 处理)
已编辑:目前我发现该问题与 CSRF 令牌有关。无论我如何从 UI 发送此令牌,它都不会在 back-end 上处理,我总是会收到 "Invalid CSRF token" 错误。
我尝试将 _token 字段直接添加到 json object 并将字段名称设置为 _token 通过csrf_field_name
选项进入我的表单类型 class.
我也尝试将 json_decode($request->getContent(), true)
传递给我的表单 submit()
方法,但调试后我发现,提交的数据在下一个代码中发生了变化:
// Symfony/Component/Form/Form.php, submit() method
if ($dispatcher->hasListeners(FormEvents::PRE_SUBMIT)) {
// here submittedData has csrf _token key/value
$event = new FormEvent($this, $submittedData);
$dispatcher->dispatch(FormEvents::PRE_SUBMIT, $event);
$submittedData = $event->getData();
// now submittedData without _token key/value
}
EDITED2:更多细节。 CsrfValidationListener
使用 Symfony Form 组件调用 $this->tokenManager->isTokenValid(new CsrfToken($this->tokenId, $data[$this->fieldName]))
而这个 return 错误,下一个代码中的问题:
// Symfony/Component/Security/Csrf/CsrfTokenManager.php
public function isTokenValid(CsrfToken $token)
{
if (!$this->storage->hasToken($token->getId())) {
return false;
}
return StringUtils::equals($this->storage->getToken($token->getId()), $token->getValue());
}
似乎 csrf 令牌存储在 session 中,所以 isTokenValid()
方法 return false
.
我继续调试
EDITED3:
如我所见,session 在从 CsrfTokenManager.php 调用 $this->storage->hasToken($token->getId())
时为空。
这很奇怪,因为我通过以下方式从我的控制器生成 csrf 令牌:
$csrfToken = $this->get('security.csrf.token_manager')->refreshToken('Symfony');
正如我所见,refreshToken() 方法将 csrf 令牌保存到 db:
// Csrf/CsrfTokenManager.php
public function refreshToken($tokenId)
{
$value = $this->generator->generateToken();
$this->storage->setToken($tokenId, $value);
return new CsrfToken($tokenId, $value);
}
// Csrf/TokenStorage/SessionTokenStorage.php
public function setToken($tokenId, $token)
{
if (!$this->session->isStarted()) {
$this->session->start();
}
$this->session->set($this->namespace.'/'.$tokenId, (string) $token);
}
但是当我向表单发送数据时,$this->tokenManager->isTokenValid(new CsrfToken($this->tokenId, $data[$this->fieldName]))
从 CsrfValidationListener
return 的 preSubmit() 方法调用空 session.
以防万一我添加 security.yml 设置,也许我遗漏了一些东西:
main:
pattern: ^/(?!login).+
stateless: true
simple_preauth:
authenticator: app_bundle.api_key_authenticator
provider: api_key_user_provider
anonymous: ~
logout: ~
login:
pattern: ^/login
stateless: false
simple_preauth:
authenticator: app_bundle.email_password_authenticator
provider: email_user_provider
anonymous: ~
注意:我在登录防火墙下生成csrf-token并尝试从主防火墙访问它!
但我也尝试在同一防火墙中生成 csrf-token。没有任何变化。
EDITED4:
我已配置自定义 session 目录以跟踪 session 创建。所以,我可以看到,在登录时我有 session 的所有属性,但是当我执行 PUT 请求时,我注意到创建了新的 session 文件并且它包含如下内容:
_sf2_attributes|a:0:{}_sf2_flashes|a:0:{}_sf2_meta|a:3:{s:1:"u";i:1449700968;s:1:"c";i:1449700968;s:1:"l";s:1:"0";}
空着session.
所以,我找到了 csrf 错误行为的原因。
创建 csrf 令牌时,它存储到会话中。因为我的 api 防火墙是无状态的,它不能存储 csrf 令牌。而且每个身份验证会话都被删除并且只有当前身份验证令牌。
正确配置 CORS 有助于防止 csrf 攻击。
另见 this answer about CORS headers.
希望这对某些人有所帮助。
我有两个独立的项目:UI(AngularJS) 和 Server(Symfony2)。
我需要从 AngularJS 应用程序发送 cross-domain PUT 请求到 Symfony2 应用程序。
在 Symfony 控制器中,我将 $request
传递给 form->handleRequest();
并且调试显示我没有提交使用这种方式的表单。
因此,接下来我尝试将 $request
传递给 form->submit()
并得到错误 "Invalid CSRF Token"。
- 如何通过 Symfony 表单正确处理 cross-domain 数据?
我读过将
$request
传递给 submit() 方法是 被贬低了。 - 如果我从 UI 通过 headers ? (我在请求中添加了 csrf 字段,但它没有在 back-end 处理)
已编辑:目前我发现该问题与 CSRF 令牌有关。无论我如何从 UI 发送此令牌,它都不会在 back-end 上处理,我总是会收到 "Invalid CSRF token" 错误。
我尝试将 _token 字段直接添加到 json object 并将字段名称设置为 _token 通过csrf_field_name
选项进入我的表单类型 class.
我也尝试将 json_decode($request->getContent(), true)
传递给我的表单 submit()
方法,但调试后我发现,提交的数据在下一个代码中发生了变化:
// Symfony/Component/Form/Form.php, submit() method
if ($dispatcher->hasListeners(FormEvents::PRE_SUBMIT)) {
// here submittedData has csrf _token key/value
$event = new FormEvent($this, $submittedData);
$dispatcher->dispatch(FormEvents::PRE_SUBMIT, $event);
$submittedData = $event->getData();
// now submittedData without _token key/value
}
EDITED2:更多细节。 CsrfValidationListener
使用 Symfony Form 组件调用 $this->tokenManager->isTokenValid(new CsrfToken($this->tokenId, $data[$this->fieldName]))
而这个 return 错误,下一个代码中的问题:
// Symfony/Component/Security/Csrf/CsrfTokenManager.php
public function isTokenValid(CsrfToken $token)
{
if (!$this->storage->hasToken($token->getId())) {
return false;
}
return StringUtils::equals($this->storage->getToken($token->getId()), $token->getValue());
}
似乎 csrf 令牌存储在 session 中,所以 isTokenValid()
方法 return false
.
我继续调试
EDITED3:
如我所见,session 在从 CsrfTokenManager.php 调用 $this->storage->hasToken($token->getId())
时为空。
这很奇怪,因为我通过以下方式从我的控制器生成 csrf 令牌:
$csrfToken = $this->get('security.csrf.token_manager')->refreshToken('Symfony');
正如我所见,refreshToken() 方法将 csrf 令牌保存到 db:
// Csrf/CsrfTokenManager.php
public function refreshToken($tokenId)
{
$value = $this->generator->generateToken();
$this->storage->setToken($tokenId, $value);
return new CsrfToken($tokenId, $value);
}
// Csrf/TokenStorage/SessionTokenStorage.php
public function setToken($tokenId, $token)
{
if (!$this->session->isStarted()) {
$this->session->start();
}
$this->session->set($this->namespace.'/'.$tokenId, (string) $token);
}
但是当我向表单发送数据时,$this->tokenManager->isTokenValid(new CsrfToken($this->tokenId, $data[$this->fieldName]))
从 CsrfValidationListener
return 的 preSubmit() 方法调用空 session.
以防万一我添加 security.yml 设置,也许我遗漏了一些东西:
main:
pattern: ^/(?!login).+
stateless: true
simple_preauth:
authenticator: app_bundle.api_key_authenticator
provider: api_key_user_provider
anonymous: ~
logout: ~
login:
pattern: ^/login
stateless: false
simple_preauth:
authenticator: app_bundle.email_password_authenticator
provider: email_user_provider
anonymous: ~
注意:我在登录防火墙下生成csrf-token并尝试从主防火墙访问它!
但我也尝试在同一防火墙中生成 csrf-token。没有任何变化。
EDITED4:
我已配置自定义 session 目录以跟踪 session 创建。所以,我可以看到,在登录时我有 session 的所有属性,但是当我执行 PUT 请求时,我注意到创建了新的 session 文件并且它包含如下内容:
_sf2_attributes|a:0:{}_sf2_flashes|a:0:{}_sf2_meta|a:3:{s:1:"u";i:1449700968;s:1:"c";i:1449700968;s:1:"l";s:1:"0";}
空着session.
所以,我找到了 csrf 错误行为的原因。
创建 csrf 令牌时,它存储到会话中。因为我的 api 防火墙是无状态的,它不能存储 csrf 令牌。而且每个身份验证会话都被删除并且只有当前身份验证令牌。
正确配置 CORS 有助于防止 csrf 攻击。
另见 this answer about CORS headers.
希望这对某些人有所帮助。