2

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?

4

2 回答 2

4

我认为作为一般规则,您应该使代码表现得合乎逻辑,然后以其他方式扩展性能,例如更大更强大的数据库或缓存结果。

对于我的应用程序,我使用多个查询。我已经为我们的系统计时,5-10 次往返时间不到 1 毫秒。这对我来说已经足够了。我见过其他人创建复杂的存储过程来做他们想做的一切。结果是他们可以从数据库中返回 403 或 404 之类的内容。

我个人更愿意多次访问数据库,以使代码更清晰、更易于阅读。如果您的负载不太大,则尤其如此。硬件很便宜,但你的时间不是。

于 2013-07-24T03:12:06.090 回答
0

在调试了更多这些问题之后,我想添加另一个意见。

很高兴告诉用户(或应用程序代码)究竟出了什么问题。我现在常用的方法是从 SQL 返回所有相关的安全信息,然后在应用程序中进行检查。这样一来,数据库就可以进行一次往返,并且您可以从代码中提供非常详细的信息,例如“您不再有权访问该经销商”。或“这辆车已被删除。”。

于 2016-03-17T15:58:57.317 回答