Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

In auto mode, cookie_secure may not be set properly in a secure environment if session starts too soon #40221

Copy link
Copy link
Closed
@tamcy

Description

@tamcy
Issue body actions

Symfony version(s) affected: 4.4.19

Description

Recently I stumbled upon an issue that PHP isn't writing my cookie as "secure" in the output even when I

  1. am accessing the website through HTTPS;
  2. have session.cookie_secure explicitly set to "On" in php.ini, and
  3. have cookie_secure set to auto in Symfony 4.4 (which is the default).

I found this weird, because

  1. this seems to only affect the PHP session ID cookie but not those written by the sendHeaders() method in Symfony's Response object, so obviously Symfony knows it is a secure connection,
  2. this doesn't happens all time - in my setup it only affects the frontend but not the backend, and
  3. the problem goes away if I explicitly set cookie_secure to true in framework.yaml.

After several hours of debugging, I have tracked down the cause. Here's how it happens:

  1. When NativeSessionStorage is created, it calls ini_set() to replace the session-related configurations with those defined in the framework config. The values are written as-is, so when cookie_secure is set to auto in framework.yaml, this auto will be passed to ini_set. Here's the problem - auto is not a valid value for this configuration, and will probably be treated as Off or False. Which is why having session.cookie_secure set to "On" in php.ini won't help in my situation.
  2. Fortunately, this invalid value auto normally won't stay forever. The problem is fixed by Symfony\Component\HttpKernel\EventListener\SessionListener, which is activated when the framework's cookie_secure is set to auto. SessionListener checks if the request is a secure one and if yes, it sets the cookie_secure PHP option to true, thus overriding the previous incorrect value that will be intepretated as false.

Here is the tricky part. The reason the session ID cookie isn't properly written as secure even when the website is accessed through HTTPS is because in the frontend, I have an Authenticator that checks for a specific session key in the supports method. This method is executed so early in the request cycle such that the session is started before SessionListener is run. When this happens, it is too late for SessionListener to set the cookie_secure PHP option to true because NativeSessionStorage's setOption() will exit immediately if the session has been started. Now the auto value will stay till the end, which I believe will be treated as false by PHP, so the PHPSESSID's cookie will not have the secure attribute.

I don't see any warning that one should not access the session in the guard authenticator's supports() method. In fact I can find suggestion of "only return true in supports() if the user is on the correct URL and if that session key exists" in the comment section of a SymfonyCasts page, which is exactly what I was doing (the website I work on contains a frontend and backend which operate with different authenticators, and I need a bridge between them, thus the need for checking a particular session value). So I believe I am not doing something unwise.

I understand that I may have stumbled upon an edge case, and probably not much people will be affected by this. Also it's not difficult to work around this problem, I just need to defer the session checking until getUser() is called. Or I can just explicitly set cookie_secure to true to avoid this glitch. But since the consequence is security related (cookie_secure flag is not turned on even when it should), I think it would be better for me to report this issue anyway and mark it as a bug report first and let your team decide what to do with it.

Thank you!


Update 19 Feb

After some more tests, it looks like the problem is probably a more wide-spreaded one. session.cookie_secure isn't set properly (i.e. stays in "auto") even for the following controller code in a newly set up Symfony 4.4 and 5.2 project:

<?php

namespace App\Controller;

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Routing\Annotation\Route;

class MainController
{
    private $session;

    public function __construct(SessionInterface $session)
    {
        $this->session = $session;
    }

    /**
     * @Route("/")
     */
    public function index(): Response
    {
        $this->session->set('foo', 'bar');

        return new Response(ini_get('session.cookie_secure'));
    }
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.