身份认证那些事

前些天看到 “Token 认证的前因后果”这篇文章,对使用token认证已经讲得很清楚了。算法

我也回答过很多关于身份认证的问题,在这里也简单总结一下,其实理解其中的核心原理,不管用什么方案都是相通的。数据库

用户认证过程

先用一个例子来讲明一下常规的基于session+cookie的认证过程:segmentfault

1.
客户端: 我要查看用户资料 (请求API)
服务端: 你没有凭证(session_id),请先得到凭证再来,得到凭证须要你提供用户名密码。
客户端: 好的,这是个人用户名和密码
服务端: 验证经过,如今为你生成凭证,请保管好,之后只认凭证,就算阿猫阿狗拿着你的凭证来查资料,我也会给他。api

服务端生成凭证的同时,会将凭证记录在案,以便比对。
。。。安全

2.
客户端: 我要查用户资料,这是个人凭证(经过cookie传递session_id).
服务端: 好的,请稍等,我确认一下你的凭证是否真的(根椐session_id确认session存在且有效) ,OK,是真的,资料拿去。
。。。服务器

3.
客户端: 我要查用户资料,这是个人凭证.
服务端: 对不起,你的凭证已通过期失效了,请从新提供用户名密码得到新的凭证。cookie

常规处理方式

由上面例子能够看出,整个认证过程的核心是“凭证的生成和验证”, 那接下来说一下通常状况下服务端怎么生成凭证和怎么验证凭证:session

  1. 首先,生成凭证的前提条件是提供的用户名和密码是对的。
  2. 生成随机惟一的session_id, 好比md5(用户id+毫秒数)
  3. 生成session内容,并创建session_id与session内容的对应关系

    session内容通常是用户的标识信息,好比uid,也有放置更多扩展profile信息以减小查询数据库次数的
    关联便是用session_id为key保存session到文件或数据库。运维

  4. 将session_id放到cookie中响应给客户端(必要时,可将session_id加密防伪)。
  5. 客户端拿到cookie,下次请求时带上,服务端根椐cookie中的session_id,确认是否有效

JWT

最近流行一种叫JWT的认证方式,其实也是上面的变种。分布式

先简单来看看JWT原理:

a. 服务端验证经过后,生成凭证(即jwt的token)

b. 请求时带上token,服务端验证token有效,验证经过,返回结果.

若是你看过JWT约定的格式算法,那应该会发现,这个生成过程,实际上只是上面提到的“session_id生成和加密防伪”, 也就是说,JWT是将常规认证简化了(只生成了凭证,不将凭证记录在案):

JWT生成凭证时,在凭证中加入了用户信息(比如是银行存折是实名的)
凭证再也不使用cookie传输和保存
JWT的内容能够认为是明文的,只是增长了数字签名(至关银行存折,盖上大印防伪)
服务端认证时,无需再查询,直接根椐内容和签名,就能确认是否有效。(嗯,银行看一下存折,再看一下印章,就认为存折是真的,这好像有什么问题?)

有没有看出来,jwt只是换了一种说法和约定了内容格式,实际上用cookie也是同样的效果?

a. 服务端验证用户名密码正确,将用户ID等必须信息,生成一个字串,而后签名返回客户端
b. 客户端下次请求带上,服务端根椐签名确认客户端有效并从中取得用户标识来进行相关数据操做。

相对于常规方式,jwt简化了服务端的认证(从另外一个角度看,实际上是用下降安全性换来的,下文会说明)。

安全和防范

由于http协议自己无状态,因此才产生出这种的认证过程,但从认证过程能够看出,因为服务端只认凭证,这里面存在必定的安全隐患:

  1. 凭证被盗取

凭证是经过cookie传递,并保存在本机,这里头有被窃取的风险,因此须要必定的防范措施,好比:

  • 设置cookie的http_only属性
  • 使用https来传输
  • 设置凭证有效期
  1. 伪造凭证

这个很好理解,也就是说我本身造一个凭证出来骗服务器。

再来为何说jwt下降了安全性?先简单看看jwt的要点:

  • JWT的header和playload能够说是明文的(只是用base64编码)
  • playload通常会包括用户标识,否则没法肯定是哪个用户
  • header中声明了签名算法
  • 使用同一个secret

不难看出,secret是最关键的,一旦secret被获取或猜出来,那将是灾难性的后果,攻击者能绝不费力的冒充全部用户,由于用户标识通常是有规则的(好比是自增的uid),根椐这个标识和有效的jwt格式,拿到secret就能本身生成全部用户的jwt。

这就是为何不用纯cookie而要用session的缘由之一。
便是说,你就算获取了个人算法和secret,能够伪造session_id,但你不知道我有哪些session_id,尽量的减低了风险。

实际上更早期的认证方式就是用纯cookie的,JWT只是规范了认证的内容,有些文章把JWT说成是新一代的认证我是不认同的。

你可能会说,secret确定要保存好啊,这没错,但你有没想过,总有开发或运维能接触到secret吧?怎么防范?

另外,算法知道了,别有用心的人要用穷举法来猜出secret也是可能的,更可怕的是不少人的secret甚至是一些常见词语(我甚至看过有人就把“secret”做为secret的)

最后,假如原来知道secret的同窗离职了,你要修改secret吧? 但全部的token都是根椐旧的secret算出来的,你一改,就全认证失败了,这在正常业务中也是很难接受的。

session和JWT对比

session的优势是更安全,缺点是认证过程较复杂,性能相对较差(须要IO),分布式很差作,但这些缺点都已有成熟的方案来解决。

jwt的优势是认证简单、性能高、自己无状态无IO依赖自然的支持分布式随意扩展。但其缺点是安全风险较大。(这对于大部分带有敏感操做的站点或API服务是不适合的)

对于jwt的使用,我我的建议:

  • 仅将jwt用在非敏感操做的api接口
  • 若是使用jwt,尽可能使用足够复杂的secret
  • 必要时,可使用自定义的非标准加密算法
相关文章
相关标签/搜索