打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
REST 中如何安全地处理用户登录问题?
Feiox
329 2014年07月18日 提问 · 2014年07月18日 更新
  • 9 关注

    • 7 收藏,8.7k 浏览
    0

    在设计一个 App 与服务端交互的 REST 风格的 API 时,一直不知道如何处理有关用户登录的各种问题,如:

    • 判定用户是否已经登录
    • 如何对每一次 api 请求进行验证
    • 服务端与客户端通信时确保用户授权信息不被泄露。

    简而言之,如何设计用户登录?

    另:有设计过 REST API (最好是已上线的应用)的童鞋,急切地想向您求教
    My Email :Fei2037%#gmail.com My QQ:Feiox#%qq.com
    实在找不到了,只能在这里求老师 ~

    1 个回答

    8
    nightire 19.2k 2014年07月18日 回答 · 1月9日 更新

    API Server 如何处理 Authentication 其实和 REST 怎么设计没什么直接关系,REST 只是一种针对基于 HTTP 的应用(即 Web 应用)进行资源管理的设计原则,或者说就是指导你如何安排资源的一种设计理念而已。

    至于处理用户认证(登录等),那是在 REST 设计完了之后的事情,属于服务器端的应用业务逻辑。

    换言之,不管你如何设计(是否 REST,或者 REST 的正不正确,彻不彻底等等),都不会影响你处理用户认证的业务逻辑,这根本就不是非此即彼的事情。

    但是很多人搞不清楚这一点,以为实践了 REST(更不要说大部分实践都是错的,或者不够彻底的)就一切都和以前不同了,甚至以为一旦用了 REST,任何事情(比如身份认证)都有且仅有一条正确的路可走了……这一点真有些哭笑不得。

    以本问为例我们来做一个分析吧。

    首先,服务器端的身份验证基本上有两类方式:一是基于 Cookie 的验证,一是基于 Token 的验证。选择哪一种要看你的实际情况。基于 Cookie 的验证历史悠久了,原理和做法无需赘言;近几年涌现了大量的公共 API 服务,它们基本上都使用了基于 Token 的验证,这主要是因为:

    1. 处理跨域资源分享(CORS)——虽然 Cookie+CORS 也不是完全不可能,但是比较难搞

    2. 无状态性——有利于服务端扩展(伸缩性强)

    3. C/S 解藕——服务器端和客户端可以完全分离,进而静态资源可以用 CDN 来处理,服务器端完全变成 API Service

    4. CSRF Free——不依赖 Cookie,完全不担心跨域伪造请求攻击(这点尚有疑虑,有待考证)

    ……呃,忽然觉得有点跑题了,我的意思是你首先得选择一个验证方式,很明显基于 Token 的认证是趋势。

    接下来,假定选择了基于 Token 认证这条路,你首先得搞明白 Token 是怎么玩的。简单地说:客户端先发送正确的认证信息(比如电子邮件+密码),服务器端检查 OK 之后生成一个 token 返回给客户端,之后客户端所有的请求都要包含这个 token,服务器端只需要验证该 token 是否有效即可。这里有一张图,对比了 Cookie-based Authtication 和 Token-based Authentication,挺不错的:

    好,按照 REST 的设计原则,我们需要一个 Endpoint 供用户来请求认证并获取 Token,比如像这样:

    POST /authentication

    在这里,“资源”就是认证(按照 REST 的要求,用名词来表示资源),使用 POST 方法去请求,附带数据为认证用的信息,返回结果看你的业务逻辑,但至少要有一个 token。客户端拿到 token 之后,先把它存起来(比如存到 SessionStorage 里),设置请求时的 HEADER 里 Authorization 的值为 Bearer <token>,完事了。

    综上所述,这事和 REST 的关系也就是设计一个获取 Token 的 Endpoint 而已,没啥了不起的,剩下的事情都属于业务逻辑,该怎么写就看你的需求了。

     

    生成后的token不放在header,直接post过去安全吗?

    #1 苏生不惑 · 2014年07月19日 · 回复

     
    回复 苏生不惑

    实际上这是 HTTP 规范的要求。

    #2 nightire · 2014年07月19日 · 回复

     
    回复 苏生不惑

    只要通过http就有可能被截取就不安全,你可以考虑使用js在发送请求时在客户端使用加密算法计算出动态的token,不过这样只是增加了破解的复杂程度,伪造token依然是可能的

    #3 Donnie · 2014年07月19日 · 回复

     
    回复 Donnie

    用 SSL……

    #4 nightire · 2014年07月20日 · 回复

     
    回复 nightire

    有道理。。。

    #5 Donnie · 2014年07月20日 · 回复

     

    文章很详细~ 收益了~

    #6 simlegate · 2014年11月27日 · 回复

     

    好文

    #7 半卷书 · 2014年12月17日 · 回复

     

    无意中看到这篇文章, 写得真不错。 唯一一点不太敢苟同, “CSRF Free——不依赖 Cookie,完全不担心跨域伪造请求攻击”, 我的意思是,就算是 token, 获取到之后也是可以伪造请求的阿

    #8 thousand · 1月8日 · 回复

     
    回复 thousand

    跨域是不行的吧?你可以拿到我的 token,但是我会对 token 的来源加以校验,如果是来自于信任的域也就不用担心“伪造”了吧。当然我不是安全领域的专家,答案里也是参考过去学到的资料,如有疏漏还请指正细节。多谢。

    #9 nightire · 1月8日 · 回复

     
    回复 nightire

    关键就是你怎么能对来源加以校验呢? 试想一下你的 app 有 10W 用户, 分布在全国各地, 对服务器来说,每一个过来的 token 和服务器都不是一个域的. 这个没法校验的. 而通常说的跨域安全问题, 是浏览器端的安全策略, 是为了防止诸如 XSS 跨站脚本在窃取了用户信息之后将这些信息传回给自己的服务器. 浏览器限定浏览某个网站时所加载的脚本, 后续也只能够从同一个网站请求或提交资源 (比如通过 Ajax 等手段)

    #10 thousand · 1月8日 · 回复

     
    回复 thousand

    对,你说的是有没错。我个人是这么来考虑的:用户是通过登录请求来获得后续的访问 token 的,那么在处理登录请求的时候除了验证有效性之外自然也可以记录本次登录的来源域,那么此后附加了该 token 的请求自然也是同域的视为安全(服务端可以记住登录请求的来源域用以后续检查)。窃取 token 之后的访问若是来自于不同的域,则可以视为伪造请求。当然跨域安全是如你所说,主要指的是浏览器端的安全策略,由于我不是安全方面的专家,故此我能想到的验证方式大概就是以上所述。

    在实际的应用中我和我所在的团队都是直接使用了第三方的验证组件来处理 token 的事情,比如基于 JWT 的实现等等。然而很抱歉的是我对这些组件的实现细节还没有机会仔细去研究,也不知道是不是如我所想这样来处理这方面的安全问题。你的回复倒是给我提了一个醒,有必要去深究一下实现的细节,看看在这方面有没有漏洞吧。

    至于答案处列出的那几条,坦白说我也是摘抄自一些文章或文档,由于都是个人笔记留下的记录,现在也想不起来具体的出处。如果确认 token 对跨域伪造请求无能为力的话,我也会改正它。也请诸位知晓者提供可靠的佐证。

    #11 nightire · 1月9日 · 回复

     
    回复 nightire

    我觉得你第一段所说的说应该是你刚刚想出来的... 实际上 access_token/token 的设计思路不是这样的, 它并没有被设计成能够记录用户的状态, 啊, 我们这里的主题是 RESTful API, 要知道, HTTP 是无状态的. 你可以查一下业内的哪些各种服务提供商它们的 api 里的 access_token 的设计思路, 包括 OAuth2 的设计思路. 不会是用 token 来记录请求来源的.

    而且, 就算这么做, 这种方式也是有问题的, 试想我今天在上海登录了你的 app, 明天我去北京了, 难道我就得被强制下线重新登陆吗? 当然有很多服务会判断出你某次不在常用登录地点登录, 会强制让你重新登陆. 但那是 IP 层面安全机制, 不是 HTTP 的了.

    你们团队使用的第三方验证组件应该就是类似于 Google OpenID 或者提供 OAuth2.0 服务那种吧? 我基本可以肯定的是它们也不会把请求来源作为安全验证项的.

    我也不是什么安全从业者, 也没有什么全面的见解, 希望没有误导别人 :)

    #12 thousand · 1月9日 · 回复

     
    1. 是的,那是刚才匆匆想的,因为此前并没有研究过安全性的问题,所以只是个人一时的思路,见笑了。

    2. 不是 OpenID 或 OAuth 1/2,而是 JWT,详细内容可以看这里(以及下面的讨论,内容很广泛,信息量也挺大,我是留存准备有时间去研究的)https://news.ycombinator.com/item?id=7137498

    这些问题我现在无法准确翔实的回答你,不过上面的文章和讨论或许会给我们带来新的知识和见解。我粗略的阅读过它们,觉得还有很多底层的知识有待学习才能搞清楚安全方面的细节。而我们所使用的第三方组件也是通过这些资源找到的。关于 JWT 的实现 Github 上有很多,我们开始应用的时间也不算很长,目前尚未被安全问题困扰住,所以的确没什么研究,也没什么发言权。

    #13 nightire · 1月9日 · 回复

     
    回复 thousand

    另外补充一下,token 的设计思路自然不是我说的那样,但是不代表具体的实现不能扩展。我们开发的一款应用就扩展了像我所说的类似校验(但不是来源域,而是其他东西),这的确不属于广义上 token 的设计思路,但也没有违背它,目前来看工作也是正常的,只不过不涉及到防止伪造请求的安全性,所以不能算作有效的案例。

    而根据我提到的文章及讨论,貌似想要彻底安全也是几乎不太可能(目前)的,又或者需要采用多种机制来协同才能达到更高的防范要求。遗憾的是我们所做的项目还没有这么高的需求,有机会的话还真想亲自实践一把。

    #14 nightire · 1月9日 · 回复

     
    回复 nightire

    感谢兄台那么晚了还回复在下... 我们的这个辩论就暂时告一段落? 我本是嵌入式工程师, 也是前不久关注了一些网络安全方面的东西, 所以见解也很有限, 我最近也会再多了解一些这方面的内容, 有新见解也会继续在这里回复下. 望以后能继续与兄台交流 :)

    #15 thousand · 1月9日 · 回复

     

    @nightire JSON Web Token 这个解决方案就是你说的这个吧,感觉挺不错的,不知道您有试过没?

    #16 天赢金创 · 9月14日 · 回复

     
    回复 天赢金创

    没错,JWT 就是我说的基于 Token 的认证。我当然用过,事实上最好用 JWT,因为它是标准,有各种语言现成的库来处理。

    #17 nightire · 9月14日 · 回复

     
    回复 nightire

    好的,谢谢了,我去试试

    #18 天赢金创 · 9月14日 · 回复

    本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
    打开APP,阅读全文并永久保存 查看更多类似文章
    猜你喜欢
    类似文章
    一种基于RESTful的安全登陆认证方法
    OpenAPI和REST
    什么是REST?以及RESTful的实现 - 51CTO.COM
    RESTful 真正意味着什么?
    使用ASP.NET Core 3.x 构建 RESTful API - 2. 什么是RESTful API
    实施IIoT的最大挑战——工业物联网软件平台与边缘智能
    更多类似文章 >>
    生活服务
    热点新闻
    分享 收藏 导长图 关注 下载文章
    绑定账号成功
    后续可登录账号畅享VIP特权!
    如果VIP功能使用有故障,
    可点击这里联系客服!

    联系客服