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] DeprecateUserInterface &TokenInterface'seraseCredentials()#59106

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

Closed

Conversation

chalasr
Copy link
Member

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

Better avoid storing plain credentials on the security user object itself. Core no longer needs to handle this behavior to me.

Spomky and kaznovac reacted with thumbs up emojiSpomky reacted with eyes emoji
Comment on lines 7 to 8
* Deprecate `UserInterface::eraseCredentials()`, use a dedicated DTO or erase credentials
on your own e.g. upon `AuthenticationTokenCreatedEvent` instead
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Would it be possible to use__serialize()/__deserialize() instead to only serialize the intended fields? Or is this something we don't want to encourage?

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Good point, I think the DTO approach is the best but the serialization one is also validhttps://stackoverflow.com/questions/42074225/symfony-userinterface-is-serializing-the-entire-massive-user-entity. I'm going to update the deprecation messages and upgrade/changelog instructions to mention it, thanks.

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Thinking more about this, I think we should not suggest it: indefinitely keeping plain credentials on this object is likely to lead to bad situations e.g. having credentials persisted in database or exposed elsewhere e.g. logs

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

even if you have then in a non-persisted field of the entity, you will still need to configure serialization (PHP's serialization will not be impacted by which properties are mapped in the ORM metadata)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

and there is also another solution: never writing the plain password at all in your entity by using -h'hash_property_path option of the PasswordType (defined by the appropriate type extension when the password-hasher component is available) to write directly the password hash instead.

chalasr reacted with thumbs up emoji
Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Nice one

@chalasrchalasrforce-pushed thedeprecate-erase-credentials branch 2 times, most recently froma0b8874 toe622479CompareDecember 7, 2024 13:06
@chalasrchalasrforce-pushed thedeprecate-erase-credentials branch 3 times, most recently from2263cdf to3a93276CompareDecember 9, 2024 13:20
@chalasrchalasr changed the title[Security] DeprecateUserInterface::eraseCredentials()[Security] DeprecateUserInterface &TokenInterface'seraseCredentials()Dec 9, 2024
@chalasrchalasrforce-pushed thedeprecate-erase-credentials branch 2 times, most recently fromaece9de to3f2503cCompareDecember 9, 2024 14:35
@chalasr
Copy link
MemberAuthor

All comments have been addressed

@xabbuh
Copy link
Member

The verity packages job failure kids
looks related to me.

@chalasrchalasrforce-pushed thedeprecate-erase-credentials branch from3f2503c toc057ba3CompareDecember 10, 2024 00:35
@chalasr
Copy link
MemberAuthor

@xabbuh Indeed, fixed. Thank you

@@ -135,6 +135,9 @@ public function load(array $configs, ContainerBuilder $container): void

// set some global scalars
$container->setParameter('security.access.denied_url', $config['access_denied_url']);
if (true === $config['erase_credentials']) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Why don't we do this check in theMainConfiguration class instead?

@nicolas-grekas
Copy link
Member

What's the alternative? Isn't this PR making it easier to inadvertently put passwords in the session storage?

@chalasr
Copy link
MemberAuthor

chalasr commentedJan 7, 2025
edited
Loading

The alternative is to never store plain credentials in the user object especially if it's a doctrine entity but also any object that lives longer than the time required to deal with plain credentials e.g. using a DTO instead as suggested in deprec notices or just an extra form field in case of symfony/form, one that don't map to any property of the User object - that's whatmake:registration-form does for a while hence the 98% of user classes having this method empty.

@rosier
Copy link
Contributor

I'm wondering if moving the methoderaseCredentials() from theUserInterface to it's ownEraseCredentialsInterface could be a better way to allow the removal of the emptyeraseCredentials() method from the User objects and also provide a smooth upgrade path for projects that still need the feature.

Combined with not deprecating theTokenInterface or a listener that checks for theEraseCredentialsInterface.

@chalasr
Copy link
MemberAuthor

Based on my experience both as a Symfony core developer and a consultant, we don't need an equivalent given this is not needed for 90+% use case, a few sentences in the documentation are enough instead taking what we already have in term of educative content and docs into account. But maybe I'm wrong, if other core members and good part of Symfony developers think such alternative is needed in core, I will happily reconsider and smoothly turn this config option to false by default + extract this out of UserInterface.

@rosier
Copy link
Contributor

To be clear. I'm fine with completely removing the erase credentials feature.

I just figured if others see a roadblock splitting the interface might be a way out to get ride of the emptyeraseCredentials() method from the User objects.

@chalasr
Copy link
MemberAuthor

👍 I don't think we are there. Also talked about this on stage at SymfonyCon and didn't got any negative reaction, not even questions about this. The practice behind the deprecated feature is subject to trouble, I think the community already moved away from it.

Copy link
Member

@nicolas-grekasnicolas-grekas left a comment
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I think this is too abrupt.
We're forcing a deprecation on code that could be perfectly fine.
I'm fine with not forcing an empty eraseCredentials method, but not with making it harder for ppl that need a way to erase credentials.

@nicolas-grekas
Copy link
Member

nicolas-grekas commentedJan 17, 2025
edited
Loading

Note that I'm not sure putting hashed passwords in the session storage should really be encouraged, so having a non-empty eraseCrentials (as generated by maker-bundle) might not be a best-practice either.

@chalasr
Copy link
MemberAuthor

Let’s go for a dedicated interface then, leaving the config as it is today.

@stof
Copy link
Member

@nicolas-grekaseraseCredentials is not a proper solution to avoid including the hashed password in the serialized object. For that, the proper solution is__serialize.
Removing the hashed password from the object is very risky, because if you callflush() on the ORM after that, it will update thedatabase erasing the credentials (and then you cannot authenticate anymore)

@nicolas-grekas
Copy link
Member

nicolas-grekas commentedJan 17, 2025
edited
Loading

Maybe the security system should always clone the object it stores before? Because I agree mutating is risky.

@nicolas-grekas
Copy link
Member

For that, the proper solution is __serialize

I'm wondering about this also: is the proper solution to implement__serialize /__unserialize?
@chalasr you're talking about having a DTO, but I'm not sure this is really a DX-friendly alternative. I wouldn't know how to implement that in just a few lines, while I could with added serialization logic.

@stof
Copy link
Member

Having a method on the class that is unsafe to call without first cloning the object might be a footgun in projects. And this would also require that the object is cloneable, which is not a requirement today (and for instance, I'm totally not sure about whether cloning a Doctrine ORM proxy instance works fine when the proxy has not been initialized yet or whether it produces a broken instance that cannot ever be initialized, while using a Doctrine entity as the user implementation is a common case and so we could end up with a proxy instance)

@nicolas-grekas
Copy link
Member

I don't think serializing an uninitialized entity can happen: it'd mean serializing an entity who's password was never checked. From the pov of the security component, this doesn't make sense.

But cloning usingclone is not needed if that's not safe: we can instead serialize then unserialize. That's another way to clone that's explicitly required for user objects. Maybe a better way forward?

@nicolas-grekas
Copy link
Member

So, it looks like we're good with adding the suggestion of implementing__serialize() as the recommended method, isn't it?

This is somewhat related to#59562 where I explain how the magic method can be used to tweak what's serialized.
Let's update this PR to give a hint in deprecations? Also some PHP doc somewhere?

@chalasr
Copy link
MemberAuthor

Not the alternative I would take but that'll be for a blogpost, let's do it the fast way 👍 Thanks for your help on moving forward here, I'll update this asap.

nicolas-grekas added a commit that referenced this pull requestJan 29, 2025
…as not stored in the session (nicolas-grekas)This PR was merged into the 7.3 branch.Discussion----------[Security] Don't invalidate the user when the password was not stored in the session| Q             | A| ------------- | ---| Branch?       | 7.3| Bug fix?      | no| New feature?  | no| Deprecations? | no| Issues        | -| License       | MITRelated to#59106: this PR does is considering that if `$originalUser` (the object coming from the session) has a null password, then we don't consider it changed from `$refreshedUser`. Aka we don't log out the user in such case.The benefit is allowing to not put the hashed password in the session. I think that's desirable.Commits-------3d618db [Security] Don't invalidate the user when the password was not stored in the session
@chalasrchalasrforce-pushed thedeprecate-erase-credentials branch from99372fe toe36259dCompareJanuary 31, 2025 13:17
Copy link
Member

@nicolas-grekasnicolas-grekas left a comment
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Two things:

  • I think we should tell about__serialize, it's a way better alternative that doesn't require mutating the user/token objects. My review notes are in this direction.
  • I don't like the fact we have yet another option to explicitly configure just to unconfigure it on 8.1, forcing 100% of apps to add the line, and remove it in a few years. I have an idea but I need to code it - doesn't fit as a review comment and might be a dead end :)

@nicolas-grekas
Copy link
Member

See#59682 for what I had in mind.

chalasr reacted with thumbs up emoji

@chalasr
Copy link
MemberAuthor

Closing in favor of#59682

@chalasrchalasr closed thisFeb 4, 2025
nicolas-grekas added a commit that referenced this pull requestFeb 4, 2025
…`eraseCredentials()` (chalasr, nicolas-grekas)This PR was merged into the 7.3 branch.Discussion----------[Security] Deprecate UserInterface & TokenInterface's `eraseCredentials()`| Q             | A| ------------- | ---| Branch?       | 7.3| Bug fix?      | no| New feature?  | yes| Deprecations? | yes| Issues        |Fix#57842| License       | MITAs promised, this PR adds a commit on top of#59106 to improve the BC layer. This approach didn't fit in a review comment :) /cc `@chalasr`This PR leverages the new `#[\Deprecated]` attribute to decide if some `eraseCredentials()` method is to be called or not.My target DX here is to save us all (the community) from having to add `erase_credentials: false` configuration in all our apps.So, instead of having to opt-out from the deprecation using this config option, the opt-out is done by adding the attribute on the method:Before:```phppublic function eraseCredentials(): void{}```After:```php#[\Deprecated]public function eraseCredentials(): void{}// If your eraseCredentials() method was used to empty a "password" property:public function __serialize(): array{    $data = (array) $this;    unset($data["\0".self::class."\0password"]);    return $data;}```This should provide a smoother upgrade path (and maker-bundle could be updated right-away).Commits-------e5c94e6 [Security] Improve BC-layer to deprecate eraseCredentials methodse556606 [Security] Deprecate `UserInterface` & `TokenInterface`'s `eraseCredentials()`
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@fabpotfabpotfabpot requested changes

@rosierrosierrosier approved these changes

@nicolas-grekasnicolas-grekasnicolas-grekas left review comments

@jdreesenjdreesenjdreesen left review comments

@stofstofstof left review comments

@wouterjwouterjwouterj left review comments

@xabbuhxabbuhxabbuh left review comments

Assignees
No one assigned
Projects
None yet
Milestone
7.3
Development

Successfully merging this pull request may close these issues.

Move or retire UserInterface::eraseCredentials
9 participants
@chalasr@xabbuh@nicolas-grekas@rosier@stof@fabpot@jdreesen@wouterj@carsonbot

[8]ページ先頭

©2009-2025 Movatter.jp