Context: MVC web service backed by a SQL DB. Say I have a user relation in my database, and a set of relations that reference it through a chain of FKs. So for example let's say I have the table:
sales_people
car_dealership
cars
where a sales person belongs to a certain car dealership, and so do cars. Sales people should only be able to see cars that belong to their specific dealership. I have a few options here:
I can bake the authorization business logic into the SQL query itself:
SELECT *
FROM cars as c, sales_people AS sp, car_dealerships AS cd
WHERE where c.dealership_id = cd.id
AND sp.dealership_id = cd.id
AND sp.id = ?
AND c.id = ?
assuming the caller has verified that the sales_people id is legit and prevents trivial spoofing of that id, then the query above would prevent a user from getting hold of cars that aren't his. This could probably be extended to an arbitrary # of tables as long as the join isn't too massive.
Upside? One single DB call.
Downside?
- the authorization business logic here is very basic. User referenced by one of those tables? Sure, you can pass. However let's say I have to have more complex access rules. It's likely they might simply not be doable with one simple query.
- It's hard to tell if the user requested an unauthorized row OR if the row is authorized but doesn't actually exist, so that makes error reporting tricky. You wouldn't know if you should report a 200 or a 403 (although depending on the type of API you might want to always use 200 in these cases to prevent exposing too much information to an attacker).
The other option I see is to make extra queries before or after the fact to validate the data is indeed accessible to that user. E.g. get list of ids of cars the sales person is authorized to get and THEN perform the query on that subset, or the exact other way around.
The upside is obviously that I can make more calls and run more logic in the business layer and be as sophisticated as I want.
The downside is that I will be generating more DB traffic which could be a deal-breaker depending on how frequent that request is made.
I'm probably missing a few other options here, and I'd love to hear how you've solved the problem before. Is there a better way?