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

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

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

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

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

共收到 8 条回复

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 基本无法截取到有效明文)

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

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