我有一个具有各种形式的Symfony 3.3.13系统。
以这些形式实现“深层链接”,即能够单击电子邮件链接,登录,然后重定向到我添加了以下更改的表单:
配置文件
framework:
secret: "%secret%"
router:
resource: "%kernel.root_dir%/config/routing.yml"
strict_requirements: ~
form: ~
csrf_protection: ~
...
more
...
安全性
security:
providers:
zog:
id: app.zog_user_provider
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: ~
logout:
path: /logout
target: /
guard:
authenticators:
- app.legacy_token_authenticator
- app.token_authenticator
entry_point: app.legacy_token_authenticator
form_login: <--this line alone breaks CSRF
use_referer: true <--I tried partial combinations, none seems to make CSRF work
login_path: /security/login
use_forward: true
success_handler: login_handler
csrf_token_generator: security.csrf.token_manager <--added based on answer, doesn't help
src / AppBundle / Resources / config / services.yml
login_handler:
class: AppBundle\Service\LoginHandler
arguments: ['@router', '@doctrine.orm.entity_manager', '@service_container']
src / AppBundle / Service / Loginhandler.php
<?php
/**
* Created by PhpStorm.
* User: jochen
* Date: 11/12/17
* Time: 12:31 PM
*/
namespace AppBundle\Service;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
use Symfony\Component\Routing\RouterInterface;
use Doctrine\ORM\EntityManager;
class LoginHandler implements AuthenticationSuccessHandlerInterface
{
private $router;
private $container;
private static $key;
public function __construct(RouterInterface $router, EntityManager $em, $container) {
self::$key = '_security.main.target_path';
$this->router = $router;
$this->em = $em;
$this->session = $container->get('session');
}
public function onAuthenticationSuccess( Request $request, TokenInterface $token ) {
//check if the referer session key has been set
if ($this->session->has( self::$key )) {
//set the url based on the link they were trying to access before being authenticated
$route = $this->session->get( self::$key );
//remove the session key
$this->session->remove( self::$key );
//if the referer key was never set, redirect to a default route
return new RedirectResponse($route);
} else{
$url = $this->generateUrl('portal_job_index');
return new RedirectResponse($url);
}
}
}
我还确保在登录表单中启用了csrf,如下所示:
src / AppBundle / resources / views / security / login.html.twig
<form action="{{ path('app_security_login') }}" method="post" autocomplete="off">
<input type="hidden" name="_csrf_token"
value="{{ csrf_token('authenticate') }}"
>
app / config / services.yml
app.legacy_token_authenticator:
class: AppBundle\Security\LegacyTokenAuthenticator
arguments: ["@router", "@session", "%kernel.environment%", "@security.csrf.token_manager"]
src / AppBundle / Security \ legacyTokenAuthenticator
class LegacyTokenAuthenticator extends AbstractGuardAuthenticator
{
private $session;
private $router;
private $csrfTokenManager;
public function __construct(
RouterInterface $router,
SessionInterface $session,
$environment,
CsrfTokenManagerInterface $csrfTokenManager
) {
if ($environment != 'test'){
session_start();
}
$session->start();
$this->setSession($session);
$this->csrfTokenManager = $csrfTokenManager;
$this->router = $router;
}
/**
* @return mixed
*/
public function getSession()
{
return $this->session;
}
/**
* @param mixed $session
*/
public function setSession($session)
{
$this->session = $session;
}
/**
* Called on every request. Return whatever credentials you want,
* or null to stop authentication.
*/
public function getCredentials(Request $request)
{
$csrfToken = $request->request->get('_csrf_token');
if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken('authenticate', $csrfToken))) {
throw new InvalidCsrfTokenException('Invalid CSRF token.');
}
$session = $this->getSession();
if (isset($_SESSION['ADMIN_logged_in']) && intval($_SESSION['ADMIN_logged_in'])){
return $_SESSION['ADMIN_logged_in'];
}
return;
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
return $userProvider->loadUserByUserId($credentials);
}
public function checkCredentials($credentials, UserInterface $user)
{
return $user->getUsername() == $credentials;
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
return null;
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
return null;
}
/**
* Called when authentication is needed, but it's not sent
*/
public function start(Request $request, AuthenticationException $authException = null)
{
$url = $this->router->generate('app_security_login');
return new RedirectResponse($url);
}
public function supportsRememberMe()
{
return false;
}
}
当我在以form_login开头的security.yml中添加5行时,所有CSRF检查(包括登录表单中的检查)总是会失败。我得到的错误是:
The CSRF token is invalid. Please try to resubmit the form. portalbundle_portal_job
造成原因:
当我删除这5行时,所有CSRF令牌都起作用。
参考方案
这是我从一个启用了csrf保护的项目中获得的security.yml文件。我确实使用了FOS UserBundle,它看起来与您的FOS UserBundle不同,但是您可能会在这里看到一些有用的信息。具体来说,必须指定一个csrf生成器以使用FOS UserBundle(在防火墙下:main:form_login)。我还具有access_control模式设置,以便仅当用户通过特定角色进行身份验证时才可以访问某些终结点-但我认为这不会影响csrf。见下文:
security:
encoders:
FOS\UserBundle\Model\UserInterface: bcrypt
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
providers:
fos_userbundle:
id: fos_user.user_provider.username
firewalls:
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_token_generator: security.csrf.token_manager
logout: true
anonymous: true
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, role: ROLE_ADMIN }
- { path: ^/event, role: ROLE_USER }
同样在我的主要config.yml中,我在框架下启用了csrf。这是整个过程的片段:
framework:
#esi: ~
translator: { fallbacks: ["%locale%"] }
secret: "%secret%"
router:
resource: "%kernel.root_dir%/config/routing.yml"
strict_requirements: ~
form: ~
csrf_protection: ~
AJAX + PHP +下载mPDF生成的文件 - php我正在创建一个应用程序,用户可以访问查看表中显示的许多PDF。每行还具有复选框,允许用户检查或不检查我稍后将描述的下一个动作。这些复选框位于表单标记内,然后是一个提交按钮,该按钮通过POST方法通过AJAX REQUEST将数组内的所有文件ID发送到PHP文件。AJAX请求如下所示:$.ajax({ url: link, type: 'POST…
相对+基本URL到绝对URL? - php基本上,给定基本网址,例如file:///path/to/some/file.html 还有一个相对URLanother_file.php?id=5 我要出去file:///path/to/some/another_file.php?id=5 我找到了this script(与this one相同),但是在file://方案上似乎不起作用。在使用代码之前,我…
jQuery的Zend Form AJAX弹出窗口 - php如何执行以下操作:我想要一个链接[上传图片],它会弹出模式形式,当用户填充它时,将处理该表单。(问题不在于上传,可以是联系表格或其他任何形式)。我的问题是,当验证失败时,如何显示表单和服务器端验证消息。我已经找到了本教程:http://www.whitewashing.de/blog/articles/92,但它似乎已经很老了。 参考方案 简单的JQuery…
PHP:不推荐使用password_hash的'salt'选项 - php我正在使用密码哈希进行注册。我需要手动创建Salt,以下是我使用的代码:$options = [ 'cost' => 11, 'salt' => mcrypt_create_iv(22, MCRYPT_DEV_URANDOM) ]; $password = password_hash( $this->…
PHP-全局变量的性能和内存问题 - php假设情况:我在php中运行一个复杂的站点,并且我使用了很多全局变量。我可以将变量存储在现有的全局范围内,例如$_REQUEST['userInfo'],$_REQUEST['foo']和$_REQUEST['bar']等,然后将许多不同的内容放入请求范围内(这将是适当的用法,因为这些数据指的是要求自…