新手问题 RESTful 接口如何保证客户端请求的用户唯一性

bpw11320 · 2015年06月29日 · 最后由 wppurking 回复于 2015年06月29日 · 5628 次阅读

我们接口开发遇到一个问题,是这样的。例如我们使用 oauth 2.0 的密码协议认证。用户登录后认证系统给一个有时效性的 token,然后客户端每次请求的时候带上这个 toekn 访问 restful 资源。但是遇到一个蛋疼的问题就是怎么保证用户请求的资源是合理的。

场景: 用户 A 要删除他的车辆信息。那么 client 提交过来 用户主键和车辆主键,先判断当前车辆是否属于当前用户则数据可以进行删除动作。这时候如果他人拦截模拟登录,然后传递一个非当前用户的主键(胡乱编造的主键)然后主动探测的模式去匹配对应的主键,去恶意删除他人的用户信息。这样就会出现非常大的危害。例如:所有主键都是通过自增的方式生成的,这样恶意删除的几率就会大得多。

怎么样才能避免这种情况出现呢?之前也没设计过关于 restful 相关的内容,也没有这方面的经验。 有种本方法可以实现,就是 把 token 和 用户信息在后端绑定(有点像 session 的形式),但是感觉这种又违背了 restful 的原则。有没有好的解决方案,或者我理解上的问题?

token 当然要和用户绑定啦。

你不应该将提交用户 id 信息暴露给互联网。

"用户删除他的车辆" 的 Public API 可以考虑仅仅设计一个参数 "car_id" 同时应该为 DELETE 提交 (至少为 POST), 因为

  • 哪个用户在执行操作,通过 token 信息告诉你
  • 用户要删除 card 的功能,通过设计好的具体 API 地址信息告诉你
  • 用户对资源的删除操作,通过 Restful 中的 DELET 信息告诉你
  • 最后用户要操作的是哪一个具体 "资源" , 则需要通过用户主动输入的 参数 id 告诉你。

另外 token 一定是需要与哪一个用户绑定,如果 token 不与用户绑定,那整个网站的操作不久乱了,一个 token 所有用户的"资料"都可操作。Public API 应该设计为 state less 的,并且避免使用 cookie 来协助保存用户状态。每一次的 API 调用都应该携带上与某一个用户关联的有时效性的 token.

可以把这个 token 的概念联想一下

  • 每一次的 API 请求都带上 username 与 password.
  • 用户的 username 与 password 都是存储在数据库。
  • 通过 username 与 password 去寻找唯一的用户,所有的资源都与某一个用户相关,只能操作自己的资源。

此问题想远一点会扩展到另外一个 Web 安全的话题:CSRF 通过 token 的方式来进行 API 验证的时候,对于 CSRF 的预防就好比"用户登陆网站", 对于用户账户密码信息被盗的预防 (对用户 Token 被盗的预防).

#1 楼 @rei 那这样不就和 session 差不多了啊,restful 不是 无状态的吗?这样就有后端用户状态了呀。

#2 楼 @wppurking 谢谢这么晚了还过来回复帖子。

每次请求带上 账号和密码肯定不行的,感觉还是 token 的模式比较合理。access_token 的设计本来就是为了减少 账号密码的曝光程度,防止传输过程中被抓包。所以一次认证授权,返回访问令牌。我感觉使用 cookie 也好 使用 自定义 header 也好,其实都是一种状态的描述。

还有你讲到的 state less 这种设计是减少状态的存在并不是不需要状态,我这样理解对吗?

1) 是的,你就拿 token 当 session 用。 2) 你应该是误解了 http "无状态"的意思。参考

#5 楼 @ch3n 也就是说”statelessness“其实是不保证每次请求对后台都是相同的咯。他们没有统一的标示的,是这样的吗? 那就有另外一个疑问了,token 算不算共同的标示呢?

#6 楼 @bpw11320 不是统一标识的问题,是 http server 不关心你,只是把你的请求解析了交给 app server. app server 处理完了把结果 (也就是一堆 html) 再给 http server,最后,http server 把 html 再给你,然后相忘于江湖,不关心你之前的请求,不关心你之后的请求,每个人的每次请求都一视同仁。

所以,http server 并不会因为你带了 token 就把你特殊对待. 特殊对待 token 的是你的业务逻辑代码。

@bpw11320

密码那一段是让你换一个思路思考这个请求的结构,并非推荐你这样做。使用这种结构的原因是因为你设计 Public API 的时候需要是 "无状态" .

总的来说建议你思考清楚两个问题:

  1. 无状态是什么? (HTTP, Public API)
  2. token 的作用是什么,为什么要用 Token 而非用户名密码? (多想想除了显而易见的 "减少账户密码的曝光" 还有什么其他原因?, 因为传输过程中的数据使用 SSL 基本无法截取到有效明文)

多想想再找找资料,设身处地的想想,如果你设计这个东西会怎么设计?

需要 登录 后方可回复, 如果你还没有账号请 注册新账号