Problem/Motivation
#2846554: Make the PathItem field type actually computed and auto-load stored aliases made it possible to read PathItem
fields in GET
responses for REST API requests for entities. Hurray!
What we did not explicitly test, is that it also works for PATCH
, and that it then respects create url alias
This was discovered after #2824851 was committed, see #2824851-117: EntityResource::patch() makes an incorrect assumption about entity keys, hence results in incorrect behavior: a security issue against Drupal core was created, because since that patch was committed, the following security vulnerability was introduced:
Steps to reproduce
- Install a new 8.4.x site (standard profile).
- Enable path, node, hal, basic_auth.
- Create a user with create/edit node permissions, but no path alias permissions.
- Create a node the user can edit.
- As that user, submit a GET request to the node to acquire its full JSON.
- As that user, submit a PATCH request with the same JSON, but changing the path alias to any valid value.
Expected result: 403
Actual result: 200, path alias gets changed successfully.(Due to little validation at this level, it is also possible to overwrite any other alias knowing its
pid
value, as well as creating path aliases that cover system routes.)
Proposed resolution
Add explicit test coverage, which would have surfaced the regression that #2824851 introduced during the patch review process. If we didn't have the vigilant @cburschka, then Drupal 8.4.0 would have shipped with this security vulnerability
Remaining tasks
User interface changes
None.
API changes
None.
Data model changes
None.
Comment | File | Size | Author |
---|---|---|---|
#12 | 2909183-12.patch | 7.86 KB | tedbow |
#12 | interdiff-5-12.txt | 1.47 KB | tedbow |
#5 | 2909183-5.patch | 7.82 KB | Wim Leers |
Comments
Comment #2
Wim LeersLet's start by adding a test to prove that it is secure in HEAD: PATCHing a node's path (URL alias) should result in a 403.
Patch lifted from #2824851-123: EntityResource::patch() makes an incorrect assumption about entity keys, hence results in incorrect behavior.
Comment #3
Wim Leers#2 added sensible security coverage. But to really know for certain that things are working as expected, we should expand the test coverage to verify that granting the
create url aliases
permission then results in a 200 response: granting the necessary permission does allow thepath
field to be changed.Note that there are three entity types that have a
path
field:node
+term
+media
. The latter doesn't have any REST test coverage yet, so we leave that one out of consideration. Back when we worked on fixingpath
fields handling in #2846554: Make the PathItem field type actually computed and auto-load stored aliases, we chose to useNodeResourceTestBase
to NOT GRANT thecreate url aliases
permission by default, and to useTermResourceTestBase
to GRANT thecreate url aliases
permission by default, i.e. they'd be each other opposites.For that reason, we should also add similar test coverage to
TermResourceTestBase
as #2 already did forNodeResourceTestBase
. But rather than expecting a 403 response, we should expect a 200 response.Now we have the test coverage we need!
Except this is going to fail… changing path aliases doesn't work at all in HEAD :( But at least the permission is respected as it should!
Patch lifted from #2824851-124: EntityResource::patch() makes an incorrect assumption about entity keys, hence results in incorrect behavior.
Comment #4
Wim LeersThis is the failure:
(The latter is what is expected. The former shows what is actually stored — in other words: nothing was changed.)
This is failing because
PathItem::setValue()
is not callingPathItem::ensureLoaded()
. But doing that triggers an infinite loop… 😵 Fortunately that's easy to work around! 🙏Patch lifted from #2824851-126: EntityResource::patch() makes an incorrect assumption about entity keys, hence results in incorrect behavior.
Comment #5
Wim LeersFor
*HalJson*Test
tests, I had to useremoveFieldsFromNormalization()
, notunset()
, so that fields moved to_links
also are removed for the HAL+JSON normalization.Patch lifted from #2824851-134: EntityResource::patch() makes an incorrect assumption about entity keys, hence results in incorrect behavior.
Comment #8
Wim LeersAlright, this patch is green, and ready for final review :)
Comment #9
Wim Leers@dawehner made this remark over at #2824851-133: EntityResource::patch() makes an incorrect assumption about entity keys, hence results in incorrect behavior:
AFAICT you can't, because of
\Drupal\path\Plugin\Field\FieldType\PathItem::__get()
.Comment #10
tedbowLooks good, great work!
Comment #11
catchThe explanation in #9 is useful, but it should be an inline comment in the patch.
Comment #12
tedbowI was going to add an inline comment per #11 but I didn't really understand the explanation in #9 when I looked back at it. Maybe I forgot something because I did RTBC this issue
Anyways here is a patch that does change to class based variable. I can't see what it will break.
Comment #13
Wim LeersHuh. I'd swear the explanation in #9 was accurate.
But I just stepped through it with a debugger and indeed was not a problem. I could not get the problem I described in #9 to get triggered. So I must've been wrong. I probably mixed two things up.
I of course like this better!
Comment #14
catchGlad I asked for the comment :)
Committed/pushed to 8.5.x and cherry-picked to 8.4.x. Thanks!
Comment #17
Wim LeersDefinitely! :)
This unblocks #2824851: EntityResource::patch() makes an incorrect assumption about entity keys, hence results in incorrect behavior, yay!
Comment #18
Wim LeersOh, can you also give issue credit to cburschka? Thanks!
Comment #19
amateescu CreditAttribution: amateescu as a volunteer commentedNote that I'm basically reverting the changes that were made here to
PathItem
in #2916300-9: Use ComputedFieldItemListTrait for the path field type and it seems the new test coverage still passes.Comment #20
Wim LeersYep, makes sense — you're making the code introduced in #2846554: Make the PathItem field type actually computed and auto-load stored aliases obsolete and are replacing it with something more thorough. Hence the additional work-arounds added by this issue are no longer necessary. I'm very glad we introduced extra test coverage here that A) help ensure we don't need to fix this again, B) help validate your patch!