Movatterモバイル変換


[0]ホーム

URL:


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

Sign up
Appearance settings

[Security] Hiding userFqcn in RememberMe cookie#59232

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
thereisnobugs wants to merge1 commit intosymfony:7.4
base:7.4
Choose a base branch
Loading
fromthereisnobugs:7.3

Conversation

thereisnobugs
Copy link

@thereisnobugsthereisnobugs commentedDec 17, 2024
edited
Loading

QA
Branch?7.3
Bug fix?no
New feature?no
Deprecations?no
IssuesFix#42349
LicenseMIT

In the current implementation, RememberMeDetails stores the userFqcn field, which exposes the class name of the user. This can potentially lead to information leakage about the application's internal structure.

This PR replaces the storage of userFqcn with its hash. By doing so, the implementation details of the application remain protected.

This change isnot backward compatible for the following reasons:

  1. Data stored using the old format (with userFqcn) will no longer be compatible with the new implementation.
  2. The getUserFqcn method will be replaced

If this approach is acceptable, I will adjust the implementation to ensure compatibility by:

  1. Deprecating the getUserFqcn method.
  2. Introducing a new method (e.g., getUserFqcnHash) to handle the hashed value while maintaining support for the old userFqcn field during a transition period.

Let me know if this approach works for you, and I will update the PR and fix tests.

eryshkov, zavodnoyapl1992, andrew-demb, lobster-tm, kaznovac, antonkomarev, and chapterjason reacted with thumbs up emoji
@lobster-tm
Copy link

Wait this feature, cause now everyone can spot the framework type and moreover a specific version of symfony. It's security risk.

thereisnobugs, rwqra, zavodnoyapl1992, and chapterjason reacted with thumbs up emojithereisnobugs, rwqra, and zavodnoyapl1992 reacted with heart emoji

@symfonysymfony deleted a comment fromcarsonbotJan 7, 2025
@symfonysymfony deleted a comment fromcarsonbotJan 7, 2025
@nicolas-grekas
Copy link
Member

We've been wondering about the same many times.
The BC aspect is critical, the current PR cannot be merged.
Why do we need the hash at all? Maybe we can just remove it?
Then, we need to find a BC-friendly path forward.

chapterjason, thereisnobugs, and IndraGunawan reacted with thumbs up emoji

@thereisnobugs
Copy link
Author

We've been wondering about the same many times. The BC aspect is critical, the current PR cannot be merged. Why do we need the hash at all? Maybe we can just remove it? Then, we need to find a BC-friendly path forward.

I've carefully reviewed the tests and code again. It turns out that I missed some places where theuserFqcn is used. I've made the necessary adjustments in this update.

I believe it is important to store some identifier in the cookie to associate it with the user class. Removing the class identifier entirely might lead to a potential security issue if a user with the same identifier but a different class is created. While I can't provide a concrete proof of concept for this, I think adding such an identifier would add an extra layer of safety.

In fact, the check forFQCN is already used in\Symfony\Component\Security\Http\RememberMe\PersistentRememberMeHandler::consumeRememberMeCookie, which further confirms the necessity of handling it properly.

To achieve this, I propose replacinguserFqcn with a hash of theFQCN (e.g., a SHA-256 hash). This approach strikes a balance between preserving security (as it doesn't expose the internal structure of the application) and ensuring unique identification of the user class.

The BC aspect is critical, and if anyone relies on the\Symfony\Component\Security\Http\RememberMe\RememberMeDetails::getUserFqcn method for their own purposes, this change could cause issues. So I could implement a transitional solution: in the current version, mark thegetUserFqcn method as deprecated and introduce a newgetUserFqcnHash method. In future versions,getUserFqcn would be fully replaced bygetUserFqcnHash.

What do you think about this approach?

@thereisnobugsthereisnobugs marked this pull request as ready for reviewJanuary 21, 2025 08:10
@carsonbot
Copy link

Hey!

I see that this is your first PR. That is great! Welcome!

Symfony has acontribution guide which I suggest you to read.

In short:

  • Always add tests
  • Keep backward compatibility (seehttps://symfony.com/bc).
  • Bug fixes must be submitted against the lowest maintained branch where they apply (seehttps://symfony.com/releases)
  • Features and deprecations must be submitted against the 7.3 branch.

Review the GitHub status checks of your pull request and try to solve the reported issues. If some tests are failing, try to see if they are failing because of this change.

When two Symfony core team members approve this change, it will be merged and you will become an official Symfony contributor!
If this PR is merged in a lower version branch, it will be merged up to all maintained branches within a few days.

I am going to sit back now and wait for the reviews.

Cheers!

Carsonbot

@nicolas-grekas
Copy link
Member

I think we don't need to leak anything about user's FQCN, not even a hash:

  • for persistent tokens, we store the FQCN in the storage, so we can use it to compare
  • for non-persistent, we can add the FQCN to the signature

Do you think that's doable?

thereisnobugs reacted with hooray emoji

@nicolas-grekas
Copy link
Member

Self-analyzing my proposal :D

for non-persistent, we can add the FQCN to the signature

That'd mean not being able to validate the signature before calling the user provider, which means opening a timing-attack vector.

So a hash looks required then, but only for non-persistent ones.
Then, this hash shouldn't be a straight sha256 of the FQCN, because then I could still trivially guess the FQCN by building some rainbow table with precomputed and likely FQCNs (eg containingsha256(App\Entity\User), etc.)
To fix this, we could compute the hash by hashing the signature and the FQCN together. WDYT?

thereisnobugs reacted with thumbs up emojithereisnobugs reacted with eyes emoji

@nicolas-grekas
Copy link
Member

Up to dig this idea@thereisnobugs?

thereisnobugs reacted with thumbs up emojithereisnobugs reacted with eyes emoji

@thereisnobugs
Copy link
Author

@nicolas-grekas

Sorry for the delayed answer. I've had a lot of work.

I dug deeper and realized that fornon-persistent tokens in Symfony, FQCN is not used at all. If we remove this property, nothing will change in terms of signature calculation and verification. The only potential compatibility issues would occur if someone is relying on this data in their implementation.
In that case, we could deprecate this property and introduce a transition period and then remove this.

Persistent tokens are more complicated. Before checking the token, userIdentifier and userFqcn are compared.
I also found that for persistentToken to have an FQCN, $user::class is written into $tokenValue in RememberMeDetails and stored in the cookie.
I believe the idea behind storing FQCN for persistent tokens was for security reasons. Hypothetically, someone could have two different user classes with the same UserIdentifiers. In some cases, it might be possible to create a user with a different FQCN but the same UserIdentifier (e.g., "admin") and gain more privileges than intended.
It seems to me that there are at least two possible solutions:

  1. Hash TokenValue and FQCN
    Modify \Symfony\Component\Security\Http\RememberMe\RememberMeDetails::fromPersistentToken:
// \Symfony\Component\Security\Http\RememberMe\RememberMeDetails::fromPersistentTokenpublic static function fromPersistentToken(PersistentToken $persistentToken, int $expires): self{    return new static($persistentToken->getUserIdentifier(), $expires, $persistentToken->getSeries().':'.hash('sha256', $persistentToken->getTokenValue().$persistentToken->getClass()));}

and change the token verification method:

 public function verifyToken(PersistentTokenInterface $token, #[\SensitiveParameter] string $tokenValue): bool {     if (hash_equals(hash('sha256', $token->getTokenValue().$token->getClass()), $tokenValue)) {         return true;     }     // ...
  1. Use a more complex hash in \Symfony\Component\Security\Http\RememberMe\RememberMeDetails::toString
    Instead of storing FQCN as is, store a hash of the concatenation of FQCN and tokenValue and compare this hash as I suggested before, for example:
public function toString(): string{    return implode(self::COOKIE_DELIMITER, [hash('sha256', $this->userFqcn, $this->value), strtr(base64_encode($this->userIdentifier), '+/=', '-_~'), $this->expires, $this->value]);}

I think this should be enough, since the main idea is to make it less obvious from the cookie signature that we are using Symfony and PHP.

@nicolas-grekas
Copy link
Member

I don't think this same-user-identifier/different-fqcn exists. In the end userProvider->loadUserByIdentifier is called, so that there's only one user with said identifier.

What about just deprecatingRememberMeDetails::getUserFqcn() andPersistentTokenInterface::getClass()?

Then of course we'll need to find a proper BC layer with support for existing cookies/databases.

thereisnobugs reacted with thumbs up emoji

@nicolas-grekas
Copy link
Member

WDYT@wouterj maybe?

@chalasr
Copy link
Member

I don't think this same-user-identifier/different-fqcn exists.

It does, migrating a legacy codebase or merging two projects with users in common for example.

@nicolas-grekas
Copy link
Member

nicolas-grekas commentedFeb 21, 2025
edited
Loading

It does, migrating a legacy codebase or merging two projects with users in common for example.

Can you expand? signature-based remember-me don't use the FQCN, so this doesn't apply to them.
Then what's different with persistent tokens?
If one has a remember-me cookie, the user-identifier is the only thing we need to know to reconnect the user.
Why would the internal implementation matter to end users?

@fabpotfabpot modified the milestones:7.3,7.4May 26, 2025
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@chalasrchalasrAwaiting requested review from chalasrchalasr is a code owner

Assignees
No one assigned
Projects
None yet
Milestone
7.4
Development

Successfully merging this pull request may close these issues.

RememberMe cookie should only contain the bare minimum of details
6 participants
@thereisnobugs@lobster-tm@nicolas-grekas@carsonbot@chalasr@fabpot

[8]ページ先頭

©2009-2025 Movatter.jp