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

bpw11320 · June 29, 2015 · Last by wppurking replied at June 29, 2015 · 5627 hits

我们接口开发遇到一个问题,是这样的。例如我们使用 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 基本无法截取到有效明文)

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

You need to Sign in before reply, if you don't have an account, please Sign up first.