Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Potential security holes with merge params #134

Open
theGC opened this issue Nov 29, 2020 · 2 comments
Open

Potential security holes with merge params #134

theGC opened this issue Nov 29, 2020 · 2 comments

Comments

@theGC
Copy link

theGC commented Nov 29, 2020

I've been working with this database adapter and the functionality is amazing. That said I became a little concerned that the old adage "with great power comes great responsibility" is perhaps being overlooked by the merge params, expressly: mergeAllowInsert and mergeAllowUpsert.

When testing an app which has users connected to other users via a RelationMapping, say friends I found as expected I was able to use eager loading, graph inserts and upserts. Where I became concerned was with the potential opacity of what's happening under the hood. As we are utilising objections model to insert or update these users I worry that developers may not realise that the hooks they place within Feathers to create, patch or update users will be bypassed.

Whilst I appreciate we have controls to limit the actions an external request can take, namely, via upsertGraphOptions, the requirement to effectively shut down options didn't immediately spring to mind when working with services where I hadn't specifically enabled GraphUpserts or GraphInserts, i.e.

app.use('/users', service({
    model: User,
    allowedEager: 'friends',
})

The above service looks on the face of it perfectly safe, I haven't enabled GraphUpserts or GraphInserts so these are both null. I therefore wouldn't be inclined to set any properties for insertGraphOptions or upsertGraphOptions as they aren't needed. However, the ability to utilise merge params on the external requests throws all my assumptions out the window. If the end-user realises that friends is a RelationMapping they can override my service options and do something like the following:

app.service('users').patch(my.id, {
    friends: [{
        name: 'bad user',
        role: 'admin',
        email: 'foo@foo.com',
        password: 'secret',
    }],
}, {
    provider: 'rest',
    authentication: {
        strategy: 'jwt',
        accessToken: my.accessToken,
    },
    mergeAllowUpsert: 'friends',
})

This means requests like the above can be used to generate new users or modify one's self, potentially elevating privileges or just updating things that they shouldn't. The issue here is that I can put Feathers hooks in place that prevent malicious requests on create / patch / update and reject them. However, because upsertGraph and insertGraph are dealing directly with an Objection model we skip those hooks and I'd assume most developers wouldn't think through all the scenario's like above that they need to protect against.

I feel that the benefits the merge params provide are somewhat dwarfed by the security holes they might unwittingly open up. Personally, I'd either remove them or guard against the above by turning them off by default. Then by asking developers to enable them, they hopefully also think through what they need to guard against.

I put a CodeSandbox together to show what I'm concerned about:

https://codesandbox.io/s/feather-objection-security-testing-lhw46?file=/package.json

Once it's loaded you can hit the little + icon to the right side of the terminal tab (below the down arrow):

Screenshot 2020-11-29 at 17 03 53

Then enter npm run mocha to run the tests:

Screenshot 2020-11-29 at 17 04 15

and you should get the output below:

Screenshot 2020-11-29 at 17 04 49

I've tried to put together as simple a project as I could. The service has before hooks for create, patch and update that strips any role passed to it. Furhermore, the service doesn't allow graph insert or upserts by default.

These settings and hooks are then shown to be null and void by the last 3 tests which manipulate external requests via the merge params. Allowing us to elevate a users role to admin.

Whilst I appreciate I could do a lot more to prevent this within the Feathers hooks my concern is the opacity of how it's done means developers might never think to.

@theGC
Copy link
Author

theGC commented Dec 2, 2020

here's the GitHub repo for the demo I made: https://github.com/theGC/feathers-objection-merge-request-testing

@dekelev
Copy link
Member

dekelev commented Dec 12, 2020

@theGC, Thanks for the detailed report and demo.

params in Feathers service calls are considered safe, because the client-side cannot pass them as is in service calls. Each param would need to be approved explicitly in the server-side using something like the paramsFromClient hook.

I personally do not use the insert/upsert features in my projects, but there's a similar behavior with allowedEager & mergeAllowEager that I use and it is safe enough in my opinion.

Maybe a new rule can be added to enforce that allowedEager is not set to null or undefined when mergeAllowEager is used, so that a developer would require to at least set service.options.allowedEager to an empty string/object if he wants the service to support the mergeAllowEager params operator.

An equivalent enforcement can be set on the mergeAllowInsert & mergeAllowUpsert params. What do you think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants