- Sponsor
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
I'm opening this debate after some private discussions in Slack.
The question is: are the EasyAdmin signed URLs a truly useful feature ... or are they cumbersome and unneeded because they provide a false sense of extra security?
Backend URLs are signed by default (you can disable that) via the UrlSigner
based on (copied from) Symfony: https://github.com/EasyCorp/EasyAdminBundle/blob/4.x/src/Router/UrlSigner.php
We don't sign all query params, because it's "technically impossible". We don't sign things like search queries and filters, because they are dynamic and would need signing URLs in JavaScript (which currently we can't do).
The idea is that by signing the main query params, we're protected against these:
* Instead of signing the entire URL, including all its query parameters,
* sign only a few parameters that can be used to attack a backend by:.
*
* * Enumerating all entities of certain type (EA::ENTITY_ID)
* * Accessing all application entities (EA::CRUD_CONTROLLER_FQCN)
* * Accessing any CRUD controller method (EA::CRUD_ACTION)
* * Accessing any application route (EA::ROUTE_NAME)
* * Meddling with the parameters of any application route (EA::ROUTE_PARAMS)
However, and considering that all real backends are already security-protected, is this true? An already-logged user in the backend can access to all entities (except if some voter prevents them accessing some entity). They can access to all entities via pagination and searching, so not allowing them to change the URL query param won't prevent them from accessing to those entities.
It's probably the same for the other parameters. E.g. not allowing them to change the route param is a minor extra protection, because if that URL is really important, it will have its own security restriction defined, so the user won't be able to access to it anyways, even if they can change the route name in the URL.
The best cloud services such as AWS, Azure and Google Cloud only sign URLs for features related to downloading resources/files ... to protect and time-limit the download of those resources.
So, should we stop signing backend URLs?
Activity
jmsche commentedon Feb 2, 2022
I'm not sure I understand the issue here.
The feature is already present and can be disabled, so why should it be dropped?
ioniks commentedon Feb 2, 2022
Same as @jmsche.
When you go to entity show view for exemple, you can"t modify Id in URL and go to different ID, you have to go list and click on other show link to have this signature.
I think remove the referrer url from the query url is more needed than this or make more pretty the url.
This feature can be desativated by default if you want.
javiereguiluz commentedon Feb 2, 2022
@ioniks about "pretty URLs", our opinion is that it doesn't matter because this is a backend. About "referrer", we definitely need it to provide a nice navigation flow through the backend (we can't rely on HTTP Referrer Header because some browsers block it).
javiereguiluz commentedon Feb 2, 2022
@jmsche the question is not about enabling/disabling but about ... "is this really protecting anything? Does this really prevent you doing something that you cannot do in other ways?"
If we think this is truly useless, let's remove it. Less code to maintain and many less problems for users (including the current impossibility of generating dynamic URLs using JavaScript).
ioniks commentedon Feb 2, 2022
@javiereguiluz i think a config for have referrer in url or not is better, but it's not the question here ;)
jmsche commentedon Feb 2, 2022
I don't think this is useless, but if you have to drop it for a good reason I'm okay with this.
michaelKaefer commentedon Feb 2, 2022
I am for removing it. Nobody has found any real use case or attack where this feature protects the application in the discussion so far. Even for a signed URL we still must check for permissions (for routes, actions, entities,..). And, the Symfony security features already provide almost everything I ever needed..
Removing it means less code, less complexity, less maintainance, less issues hopefully..
I also agree to: “provides a false sense of extra security“ - unless somebody can give a real example where this really can provide security.
john-dufrene-dev commentedon Feb 2, 2022
@michaelKaefer
I think it's a not a good idea to remove URL signature. Lot's of CMS use this feature for security reasons.
First of all, it is simply possible to deactivate it if you do not wish to use it.
Then, I use it in several projects and it allows to protect the urls, we cannot access another entity if we use a UUID identifier and change it directly in URL.
javiereguiluz commentedon Feb 2, 2022
@john-dufrene-dev but, if you search in the backend for that other UUID (or part of it) you'll get that other entity and you can see its details.
In other words, can anyone prove that signing URLs protects some resource in some way that you cannot access it via a different way (e.g. via pagination, search or filtering)?
john-dufrene-dev commentedon Feb 2, 2022
@javiereguiluz Okay, I understand what do you mean, sorry my english not the best.
Url signature in my opinion makes it possible to protect a change of parameters directly in the url and therefore the injection of malicious code.
Indeed to block access to resources with filters, search or other it is necessary to use a security system like Voter.
But I don't understand why just disabled this feature if you don't need it ?
By default could be disabled too
javiereguiluz commentedon Feb 2, 2022
Why remove this (if we reach the conclusion that it doesn't protect anything at all)? Because having this feature not only means maintaining it ... but it also complicates other features; even making them impossible (e.g. because we can't generate routes dynamically using JavaScript).
Crell commentedon Feb 2, 2022
I am not a security expert by any means, but I don't really see what benefit it offers. I would be fine seeing it go away.
ioniks commentedon Feb 2, 2022
If another user send you a link with delete thing and change the ID for exemple the id of your account or the admin account.
You can broke your app.
michaelKaefer commentedon Feb 2, 2022
@ioniks This sounds like a CSRF attack, I think you should be protected against it by using Symfony forms out of the box. I did not test it now but I think it is like that. For deleteions I'm not sure now if forms are used or if there is any CSRF protection in EA (I would strongly guess there is), I could check that the next weeks. Also I'm not sure if deletions are possible in EA with a GET request (= clicking on a link), I did not test it now.
fabpot commentedon Feb 2, 2022
I would love to see this "feature" removed. I seems it gives a false sense of security, security that should already be covered by Symfony via security, access control, XSS, CSRF, ...
7 remaining items
javiereguiluz commentedon Feb 4, 2022
@richard4339 as explained in https://symfony.com/bundles/EasyAdminBundle/current/dashboards.html#dashboard-configuration you can disable signatures just by calling one method on your dashboard:
richard4339 commentedon Feb 4, 2022
Thanks @javiereguiluz I'd completely missed that.
michaelKaefer commentedon Feb 4, 2022
@javiereguiluz Thank you for your infos! In my fix #4981 I missed to fix the CSRF problem so I think this must be done before removing the URL signatures like others pointed out above. I created an issue: #5028. For the actions I did a PR which adds tests.
minor #5029 Add tests for CSRF attacks (michaelKaefer)
michaelKaefer commentedon Feb 26, 2022
The PR was merged: #5028. That means that URL signatures could be removed now I guess. @javiereguiluz Did you decide yet and do you want a PR?
minor #5112 Improved the JavaScript code related to file upload files…
Amunak commentedon Aug 15, 2022
A non-obvious side effect of removing signatures is that with multiple dashboards you can bypass security set with
setEntityPermission
on a given Dashboard'sconfigureCrud
method.The documentation never really says that different Dashboards are completely separate (because they aren't), but it definitely feels that way due to how the configuration is set up.
You could have two dashboards (even in different namesapces!) that don't share any controllers, entities or anything, and rely on the Dashboard security through
setEntityPermission
. This works correctly when you only use internally generated links (except for an edge case where AssociationField automatically links to the target CRUD controller that's supposed to be displayed under a different dashboard than the one that links to it), but you can manually craft a URL with the different dashboard, and since now theconfigureCrud
method is not run (or more specifically, it's run under the other dashboard) this can lead to change in privilege requirements and access to resources the user shouldn't have access to.Importantly, the documentation also suggests that "securing the whole backend" through security.yaml's
access_control
is a good idea, which it ... isn't. It should be more explicit that it's a good first line of defense, but one should use Voters for access control and check each action properly, ignoring what dashboard it runs from.I think the documentation should be more clear about this behavior, and ideally
setEntityPermission
should not work under dashboard'sconfigureCrud
because it's meaningless.Well that, or even better, force users to explicitly "link" controllers with dashboards, so a given Controller can only be under the dasboard it's allowed to live under. This could also improve linking between Controllers of different Dashboards. Which, as a side note, is problematic - f.e. with the AssociationField.
michaelKaefer commentedon Aug 18, 2022
IMHO the app dev is responsible for configuring EA - which includes calling
setEntityPermission()
on everyDashboardController
where it's necessary.(For
access_control
vs. voters: there are apps that don't need any custom voters nor special entity permissions)Amunak commentedon Aug 19, 2022
I'm not sure you understand; when you have different dashboards that are meant to be completely separate with their separate Crud Controllers and also separate permissions, you can still use either Dashboard to render any Crud Controller that exists in your app with no limit, potentially using lower permissions to access a resource that's supposed to be better protected.
That's extremely non-obvious and IMO should be fixed or at the very least explicitly documented.
michaelKaefer commentedon Aug 19, 2022
Yes I understood it like this. I don't see a problem with this, AFAICS a CRUD controller doesn't belong to one dashboard. Maybe you can add it to the docs if you miss something. Or maybe there are more opinions.
feature EasyCorp#5084 Deprecate URL signatures and remove them by def…