Users' email addresses are one of the most important types of data when it comes to restricting access and keeping them private. A breach of confidentiality is often punishable by law with substantial fines.
The user entity had correspondingly tight access: 'access user profiles' permission gives access to the user, but the email field requires full 'administer users' permission. If an admin creates a view of users, there is no risk of exposing data even if the view has no access check.
Install simplenews module, and suddenly everything is wide open. The Subscriber entity has no access checks at all. If an admin creates a view of users with no access check, then the email addresses are public. This is not just theoretical - for a brief moment I made this mistake on a site one time.
| Comment | File | Size | Author |
|---|---|---|---|
| #34 | simplenews.access.3032167-34.patch | 518 bytes | adamps |
| #28 | simplenews.access.3032167-28.patch | 10.06 KB | adamps |
Comments
Comment #2
adamps commented@Berdir I am willing to code this, but I would like to check with you first that you agree it's a good idea. When you have some spare time, please can you let me know? Thanks.
Comment #3
berdirYeah, a lot of contrib didn't bother with field-based access as that's a new thing and wasn't really required to get things working. Core is very inconsistent too, e.g. media has a bunch of open issues around this.
Happy to improve that, that said, I'm not quite sure how that applies to subscribers, as they as a whole should be equally restricted? Field access applies when different fields have different access, e.g. user name being public and user e-mail private. So field access is generally on top of entity access, so field access is only checked when you have access to the entity.
There doesn't seem to be a reason to create a view of subscribers where some of the data should be public? So the bigger issue there is that views defaults to no access checks unless you have a custom wizard that sets a default permission?
Comment #4
adamps commentedThanks @Berdir. Apologies, I didn't actually describe what access checks I planned to add. I agree that the subscriber entity should have entity-level access and does not need field-level access. I will add a new permission 'view simplenews subscriptions' that controls access to the subscriptions of other users. Users can always view their own subscription.
I don't see that as an issue. Once we've added the entity access, it doesn't really matter if the view has no access checks - users without subscriber entity access will just see an empty page. This is the same for all entity types in core and contrib.
Comment #5
adamps commentedHere is a first attempt at a patch. No tests yet.
Comment #7
adamps commentedGuess we better not change the default access on the view
Comment #9
berdirEntity access defaults to no access, unlike fields which default to being accessible. I don't think views checks entity access like you described it, or what you did would not have been possible if the only thing we have atm is an admin permission :)
So this patch does not restrict access, it opens it up based on a new permission.
Comment #10
adamps commented@Berdir Yes you are right. We can protect access to the mail field, which then matches the user entity.
Comment #11
adamps commentedComment #12
adamps commentedComment #15
adamps commentedComment #16
adamps commentedSubscriberAccessControlHandler has two parts
1.
checkFieldAccessrestricts access to the mail field, similar to UserAccessControlHandler. This part solves the problem described in the IS.2.
checkAccessgrants access. If we are going to have a permission 'view simplenews subscriptions', then it should for sure allow that access. As @Berdir pointed out, this doesn't make any difference to views, which doesn't check entity access at all. It still seems like a good idea to make other ways of viewing subscribers work (Ajax/JSON etc?).@Berdir - I would be very grateful for your review of this one please to ensure I don't accidentally create a security bug.
Comment #17
adamps commentedHere is a new patch that corrects some errors in the previous patch, but also fixes some problems in the current code.
Where I say "SAFEGUARD" below this indicates extra checking that is a good general principle, but not really a current bug except in case of editing by some other means such as JSON.
setDisplayConfigurable()because there is no GUI to configure it anyway.Comment #19
adamps commentedOK, last fail was just a glitch. This is ready for review. I won't commit it until @Berdir has had a chance to look even if that means waiting a while because this is subtle and important.
Comment #20
adamps commentedComment #21
berdiryeah, this doesn't make sense to be configurable, was there since the first 8.x commit basically and probably copy & pasted from somewhere.
I prefer using get('status') especially in cases like this when you actually use methods on the FieldItemList object and benefit from autocomplete and code inspection.
the title was changed here because the e-mail wasn't visible anymore I think, so maybe that part isn't necessary anymore? not 100% related, so possibly better left for some other UI improvement issue.
this access check does also vary on the user not just the entity. if either the user or the entity is different, then the access result may be different.
Also, the cache contexts need to be outside of at least some of these conditions, imagine this:
* user A who is not the user connected to subscription 1 tries to edit it, he is not owner, => access denied.
* user B who is the connected user tries to access it but the previous check was cached without considering the current user, so access is denied.
What you can do to optimize it is to check the permission and operation first, then add the cache contexts, then check if it is his subscription.
Allowing this certainly makes sense for e.g. decoupled scenarios but the question is how the user finds "his" subscription in the first place, without being allowed to list them :) Because if you compare that with the default UI, that is always exposed through local tasks/a page/blocks where we look up the entity for the user. So to be able to actually make this work for decoupled sites, we'd need some kind of API that allows users to either get the ID of their subscription or a special route that works similar to the page and looks up the right subscription.
Just saying that implementing conceptually correct but not very practical ye.
Other than that stuff, this looks good, I'd just like to point out one last time that this still does not lock down access as the issue summary claims except denying edit access for the mail/langcode field if connected to a user. Everything actually adds cases where we allow more access than before. Currently we rely on "admin_permission = "administer simplenews subscriptions",", which means *anything* is only possible with that permission, now we also respect own access as well as viewing subscriptions.
Comment #22
berdirComment #23
adamps commented2. Done
3. Prior to this fix, SubscriptionsFormBase was the base class for 3 different forms, and in each case email was not visible. Just to be clear, after this fix, email is still not visible on those 3 forms. In the new code, it is
checkFieldAccess()that hides the email.4. Done, thank you - I knew you would be a great reviewer for subtle bugs in this code! It turned out to be the operation and user ID that I needed to check first.
===
Finally, thanks yes I understand that
checkAccessgrants access, see #16. So yes it isn't an essential part of the fix and I agree that it's hard to find a way to use the new access right now.Even so I believe it is important to be in this patch.
Comment #24
berdirWill check again later, to be clear, my last comment was simply about the issue summary being out of date and incorrect and we should update it because it is confusing. It does not and can not fix the mentioned views problem, the only thing that would help with that is if we'd provide a views wizard thing that sets a default access check. I agree with the changes here, but don't think it fixes any security issues. That's all I'm trying to say. That this is more a task/refactoring than a (major) bugfix.
Comment #25
adamps commentedI changed the issue title slightly to clarify it is the field access that is missing.
Well it works for me and is tested in SimplenewsAdministrationTest::testAccess().
Views makes a call to
checkFieldAccesswith items = NULL and if that fails it hides the email column.Comment #26
adamps commentedReroll
@Berdir I plan to commit this in one week. After one more week I will create a new release. Please comment if you don't want me to do that.
Comment #28
adamps commentedFix deprecation
Comment #30
adamps commentedTest failures are now same as in dev branch.
Comment #31
berdirFeel free to go ahead.
> Views makes a call to checkFieldAccess with items = NULL and if that fails it hides the email column.
True. My point is that having a subscriber view exposed to anyone makes no sense in the first place. Yes, it does hide the e-mail field, but what I was trying to get at is the the view as a whole should default to a sensible permission. Certain columns might still remain visible and configurable fields would too. But the only way to have that is a custom views wizard thingy that sets a default permission, an access control handler can't fix that.
Comment #33
adamps commented@Berdir Thanks. I agree. The subscriber view should not be exposed and this issue does not fix that. However it makes the consequences of exposing it much less bad.
Comment #34
adamps commentedSorry I was wrong about removing setDisplayConfigurable for the mail field. It is configurable at /admin/config/people/simplenews/settings/subscriber/form-display, page which I only just discovered.
Comment #36
adamps commented