Symfony2:记住我身份验证时无效的 CSRF 令牌

Posted

技术标签:

【中文标题】Symfony2:记住我身份验证时无效的 CSRF 令牌【英文标题】:Symfony2: Invalid CSRF token while remember me authentication 【发布时间】:2017-05-19 20:56:37 【问题描述】:

我有使用 Symfony 2.8.11 和 FosUserBundle 2.0.0-beta1 编写的应用程序。 用户可以通过 *** 或基本身份验证连接到站点。大多数情况下,他们在 Windows 7 上使用 Internet Explorer 11。 他们中的一些人在站点内遇到随机形式的无效 CSRF 令牌问题。问题是用户无法提交表单,即使刷新了几次页面。

我怀疑是会话不断刷新导致的问题,从日志来看:


    "created":1483610056, 
    "lastUsed":1483610056
 ["csrf","session_times"] []

此外,我怀疑它是由记住我令牌的身份验证引起的(每个问题都已通过该令牌进行身份验证):

[2017-01-05 10:54:16] security.DEBUG: Remember-me cookie detected. [] []
[2017-01-05 10:54:16] security.INFO: Remember-me cookie accepted. [] []
[2017-01-05 10:54:16] security.DEBUG: Populated the token storage with a remember-me token. [] []

我的安全配置:

...
main:
    pattern: ^/
    form_login:
        provider: fos_userbundle
        csrf_token_generator: security.csrf.token_manager
        # if you are using Symfony < 2.8, use the following config instead:
        # csrf_provider: form.csrf_provider
    logout:       true
    anonymous:    true
    remember_me:
        name: "%session_cookie_remember_name%"
        domain: "%session_cookie_domain%"
        key:      "%secret%"
        lifetime: 604800
        path:     /
    switch_user: true
...

是否有可能每次页面加载时会话都会重新启动并记住我对其进行身份验证?是错误还是正确的行为?如何解决 csrf 无效令牌问题?

问题出现时来自一页请求的完整日志:

[2017-01-05 10:54:16] request.INFO: Matched route "fos_user_profile_show". 

    "route_parameters":
    "_controller":"AppBundle\\Controller\\ProfileController::showAction",
    "lang":"pl",
    "_route":"fos_user_profile_show"
    ,
    "request_uri":"..."
 []
[2017-01-05 10:54:16] security.DEBUG: Remember-me cookie detected. [] []
[2017-01-05 10:54:16] security.INFO: Remember-me cookie accepted. [] []
[2017-01-05 10:54:16] security.DEBUG: Populated the token storage with a remember-me token. [] []
[2017-01-05 10:54:16] app.DEBUG: 

    "USER":"www-data",
    "HOME":"\/var\/www",
    "HTTP_COOKIE":"safeId=51081905; nlPopup=shown; cookieInfo=1; __cfduid=d7b03b629331902c712642a374b52b3711476715148; auth=1a2dd1f7a8b16bf7d31988bf968748b5; VMREMEMBERME=QXBwQnVuZGxlXEVudGl0eVxVc2VyOmMydHNaWEF6TkRKQVluSmhibVJpY1M1d2JBPT06MTQ4NDA1MjAxNzoyODM1NWViMThkN2EwMDQ2MGUzNzVmNzg4ZGYwYWE2NzliNTcwOGJiY2E4ZDk0ZGE4YzJhZTFmZTRlMThlMjhh; VMSESSID=4oupq2fgt72vc8lnqff0g9op44",
    "HTTP_CONNECTION":"Keep-Alive",
    "HTTP_DNT":"1",
    "HTTP_HOST":"sub.domain.com",
    "HTTP_ACCEPT_ENCODING":"gzip, deflate",
    "HTTP_USER_AGENT":"Mozilla\/5.0 (Windows NT 6.1; WOW64; Trident\/7.0; rv:11.0) like Gecko",
    "HTTP_ACCEPT_LANGUAGE":"pl-PL",
    "HTTP_ACCEPT":"text\/html, application\/xhtml+xml, *\/*",
    "SCRIPT_FILENAME":"\/data\/www\/project\/web\/app.php",
    "REDIRECT_STATUS":"200",
    "SERVER_NAME":"sub.domain.com",
    "SERVER_PORT":"80",
    "SERVER_ADDR":"x.x.x.x",
    "REMOTE_PORT":"x",
    "REMOTE_ADDR":"x.x.x.x",
    "SERVER_SOFTWARE":"nginx\/1.10.0",
    "GATEWAY_INTERFACE":"CGI\/1.1",
    "REQUEST_SCHEME":"http",
    "SERVER_PROTOCOL":"HTTP\/1.1",
    "DOCUMENT_ROOT":"\/data\/www\/project\/web",
    "DOCUMENT_URI":"\/app.php",
    "REQUEST_URI":"...",
    "SCRIPT_NAME":"\/app.php",
    "CONTENT_LENGTH":"",
    "CONTENT_TYPE":"",
    "REQUEST_METHOD":"GET",
    "QUERY_STRING":"...",
    "FCGI_ROLE":"RESPONDER",
    "PHP_SELF":"\/app.php",
    "REQUEST_TIME_FLOAT":1483610056.9177,
    "REQUEST_TIME":1483610056
 ["csrf","server"] []
[2017-01-05 10:54:16] app.DEBUG: 

    "safeId":"51081905",
    "nlPopup":"shown",
    "cookieInfo":"1",
    "__cfduid":"d7b03b629331902c712642a374b52b3711476715148",
    "auth":"1a2dd1f7a8b16bf7d31988bf968748b5",
    "VMREMEMBERME":"QXBwQnVuZGxlXEVudGl0eVxVc2VyOmMydHNaWEF6TkRKQVluSmhibVJpY1M1d2JBPT06MTQ4NDA1MjAxNzoyODM1NWViMThkN2EwMDQ2MGUzNzVmNzg4ZGYwYWE2NzliNTcwOGJiY2E4ZDk0ZGE4YzJhZTFmZTRlMThlMjhh",
    "VMSESSID":"4oupq2fgt72vc8lnqff0g9op44"
 ["csrf","cookies"] []
[2017-01-05 10:54:16] app.DEBUG: 

    "cookie":[
        "safeId=51081905; nlPopup=shown; cookieInfo=1; __cfduid=d7b03b629331902c712642a374b52b3711476715148; auth=1a2dd1f7a8b16bf7d31988bf968748b5; VMREMEMBERME=QXBwQnVuZGxlXEVudGl0eVxVc2VyOmMydHNaWEF6TkRKQVluSmhibVJpY1M1d2JBPT06MTQ4NDA1MjAxNzoyODM1NWViMThkN2EwMDQ2MGUzNzVmNzg4ZGYwYWE2NzliNTcwOGJiY2E4ZDk0ZGE4YzJhZTFmZTRlMThlMjhh; VMSESSID=4oupq2fgt72vc8lnqff0g9op44"
    ],
    "connection":[
        "Keep-Alive"
    ],
    "dnt":[
        "1"
    ],
    "host":[
        "sub.domain.com"
    ],
    "accept-encoding":[
        "gzip, deflate"
    ],
    "user-agent":[
        "Mozilla\/5.0 (Windows NT 6.1; WOW64; Trident\/7.0; rv:11.0) like Gecko"
    ],
    "accept-language":[
        "pl-PL"
    ],
    "accept":[
        "text\/html, application\/xhtml+xml, *\/*"
    ],
    "content-length":[
        ""
    ],
    "content-type":[
        ""
    ],
    "x-php-ob-level":[
        1
    ]
 ["csrf","headers"] []
[2017-01-05 10:54:16] app.DEBUG: [] ["csrf","session"] []
[2017-01-05 10:54:16] app.DEBUG: 

    "created":1483610056,
    "lastUsed":1483610056
 ["csrf","session_times"] []
[2017-01-05 10:54:16] app.DEBUG: 

    "name":"xxx",
    "address":"xxx",
    "city":"xxx",
    "phoneNumber":"xxx",
    "lang":"xx",
    "save":"",
    "_token":"ms-TX5_Du6lh3BqV2RB2CvQaEJ8WzuPBCeduAJox3ik"
 ["csrf","data"] []
[2017-01-05 10:54:16] security.DEBUG: Stored the security token in the session. "key":"_security_main" []

【问题讨论】:

可能与表单页面的浏览器缓存有关? 但为什么会话总是“新鲜”(上次使用时间 = 创建时间)? 我感觉带有令牌的会话被创建了多次,并且会话被覆盖了?是否仅当有人通过 remember-me 进行身份验证时才会出现此问题? 是的,似乎只有当 rememeber-me 完成身份验证时才会发生这种情况。我对会话的覆盖有类似的怀疑。问题是为什么应用程序会这样?我认为这不是正常行为(即使在刷新页面几次后,用户也会收到无效令牌错误)。 嗯,几乎可以肯定会话之间存在冲突。这也是使用巨大框架的一个很大的缺点,并且不知道引擎盖下到底发生了什么。除非您没有正确使用框架/组件/插件,否则可能是由不同供应商软件引起的冲突。如果没有真正理解代码(可能是很多代码),以及所有这些的正确用法和配置,解决您的问题并不容易。 FOS UserBundle 是否可能比 Symfony 形式具有单独的 csrf 保护? 【参考方案1】:

我明白了你的意思,有时这是由于 csrf 生成器而发生的。您必须更改 config.yml 文件并注释 csrf 生成器行,例如

...
main:
    pattern: ^/
    form_login:
        provider: fos_userbundle
        #csrf_token_generator: security.csrf.token_manager
        # if you are using Symfony < 2.8, use the following config instead:
        # csrf_provider: form.csrf_provider
    logout:       true
    anonymous:    true
    remember_me:
        name: "%session_cookie_remember_name%"
        domain: "%session_cookie_domain%"
        key:      "%secret%"
        lifetime: 604800
        path:     /
    switch_user: true
...

现在它们不是 csrf 令牌的条件。

【讨论】:

以上是关于Symfony2:记住我身份验证时无效的 CSRF 令牌的主要内容,如果未能解决你的问题,请参考以下文章

停止在身份验证时重新生成/使 CSRF 无效

symfony2 CSRF 无效

Jmeter 身份验证令牌

无法解释无效的 CSRF 令牌 rails api

Symfony 5 登录表单操作返回无效的 CSRF 令牌

VueJs 前端的无效 CSRF 令牌错误(symfony 5)