我们使用各种网页、app等等各端的应用,大多都会有注册登录这么一个功能,有的甚至不登录直接不能使用。
那为什么要有登录这个功能呢?
对于用户来说,他们需要保存自己独有的记录信息。我有一个朋友在手机本地玩游戏,玩了一个多月突然应用更新,他存在本地的游戏数据没了。就是因为他没有登录,没有把自己的游戏记录存到游戏服务器中,结果难受了一天。
对于公司来说,也需要保存各个用户的信息,比如说交易信息、订单记录,这样他们也方便核算。有了各个用户的账号也可以更好的为每个用户服务,推送一些有价值的信息、优惠等。
可以说,登录几乎是一个不可少的功能。
本篇文章主要讲的就是关于登录和鉴权的具体实现方式。
登录具体实现
我们知道如今在应用层发送网络请求主要用的是HTTP、HTTPS,HTTP是一种无状态协议,而HTTPS是HTTP的安全版本。
客户端每次发送请求,首先要和服务器建立连接,请求完成后断开连接,这样的话可以节省连接资源。但是这样也存在问题,服务器端无法判断不同请求是否来源于同一个用户,无法判断用户的登录状态。因此,需要一个地方来存储这个状态。
Cookie+Session
Cookie介绍
Cookie是在浏览器端存储的一小块数据,它会在浏览器向同一服务器再次请求的时候被携带。
Cookie的主要应用场景就是是Web服务器能够在用户设备上存储信息,如在线购物车中的商品、用户登录信息。可以做个性化,存储用户偏好信息,可以跟踪用户网络浏览习惯
特点
- 每次请求都会携带Cookie数据,会带来额外的性能开销
- 浏览器对每个域存储的Cookie大小有限制,一般小于4K
- 手机端很多浏览器不支持Cookie或者是禁用Cookie
存在的问题
Cookie窃取和会话劫持
- 跨站脚本攻击(Cross-site scripting,XSS)
是一种安全漏洞,攻击者可以利用这种漏洞在网站上注入恶意的客户端代码。若受害者运行这些恶意代码,攻击者就可以突破网站的访问限制并冒充受害者。
XSS 攻击的形式千差万别,但他们通常都会:将 cookies 或其他隐私信息发送给攻击者,将受害者重定向到由攻击者控制的网页,或是经由恶意网站在受害者的机器上进行其他恶意操作。
- CSRF(Cross-site request forgery,跨站请求伪造)
攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者已经验证的凭证去获取信息发到第三方网站,然后再发回客户端
很多网站利用cookie作为用户的唯一标识,但是这是存在安全风险的,攻击者可以通过窃取受害者的全套cookie来冒充用户请求。
有没有什么办法可以解决呢?
跨站脚本攻击(Cross-site scripting,XSS)
解决
- 浏览器把用户的输入当成了脚本进行了执行。那么只要告诉浏览器这段内容是文本就可以了。
- 使用白名单,禁止javascript: 链接、非法scheme
- HTTP-only Cookie: 禁止 JavaScript 读取某些敏感 Cookie,攻击者完成 XSS 注入后也无法窃取此 Cookie。
CSRF(Cross-site request forgery,跨站请求伪造)
CSRF有两个特点:
- CSRF(通常)发生在第三方域名。
- CSRF攻击者不能获取到Cookie等信息,只是使用。
因此可以有解决方案
- CSRF来自第三方网站,那么我们就直接禁止外域对我们发起请求
-
使用随机CSRF Token进行二次检查
还有一种方法是直接不使用Cookie即可
Session介绍
Session是一种会话机制,是用于保存登录状态的一种方法,Session存储在服务器端
Session主要用来维护登录状态,存储用户的一些信息。
特点
- 高并发情况下,占用服务器大量内存
可以把Session集中存储到另一个地方,比如Redis
- Session不共享问题
当把服务部署在多个不同的服务器中时,需要考虑Session共享问题
可以利用粘性Session,或者利用一个第三方存储Session,访问之前去第三方验证判断一下用户状态
- Session ID的安全性问题
不能让Session ID被轻易获取,否则会产生安全性问题。
可以产生一个不容易被猜到的Session ID值;
此外,还需要经常重新生成Session ID。在安全性要求高的场景下,可以进行二次验证,比如重新输入密码,或者使用短信验证码。
session和cookie有什么区别?
- cookie 是浏览器提供的一种缓存机制,它可以用于维持客户端与服务端之间的会话
- session指的是维持客户端与服务端会话的一种机制,它可以通过cookie实现,也可以通过别的手段实现。
- 如果用cookie实现会话,那么会话会保存在客户端浏览器中。而session机制提供的会话是保存在服务端的。
-
大小不同,cookie大小受浏览器的限制,一般是4K;session:理论上主要受当前内存的限制
认证及访问过程
认证阶段
- 前端输入用户名、密码发送请求到后端
- 后端查询数据库
-
确认用户已注册后,生成sessionId和session数据
- sessionId返回到客户端中,session数据存储在服务器端
- session是有时间限制的,过期会会话超时
- 客户端可以将sessionId放在浏览器端的cookie中
访问阶段
- 再次访问时,cookie上携带sessionId到服务器中获取相应数据
- 如果能在服务器的session表中比对到,说明用户已经登录
- 服务器就可以提取信息进行下一步操作
- 服务器还可以根据服务器中的用户信息进行角色鉴权,来判断用户是否有权限
存在的问题
-
Session开销
- 每个人登录都需要在服务器上有一块内存来存储Session,对于服务器来说是一个很大的开销
-
无法做到多端同步
- 手机端很多浏览器不支持Cookie或者是禁用Cookie
-
分布式应用要考虑Sesson同步问题,影响到可拓展性
- 粘性Session
- Session集中存储
- cookie 存在 CSRF(跨站请求伪造) 的风险。
- 需要保证session id的安全
Token
Token介绍
Token是通过服务端服务端生成的一串字符串,作为请求客户端的一个令牌,有了这个令牌就可以完成身份认证。
Token流程机制
Token本身不包含数据,它是进行用户认证会话的一个标识符
过程
- 提交用户名密码向认证服务进行请求登录
- 认证服务查询看是否存在,对此进行校验
- 如果通过则建立一个用户会话,有过期时间,可以存储在不同的端中
-
认证成功后,认证服务给客户端返回一个Token
- 根据不同的应用形式存储在不同的地方
- webMVC存储在浏览器Cookie中;单页SK应用可以存储在Cookie中也可以存在localStroge中;
-
客户端拿着这个Token去访问对应的服务
- 存储方式可以是Cookie,也可以是HTTP Header
-
对应的服务接收到Token后到认证服务进行校验
- 放到服务过滤器框架中实现
- 校验成功后返回用户信息
- 最终给客户端响应
为什么要使用Token
由于Cookie和Session无法满足多端应用的要求,如果每一个端都搞一套认证机制,成本高,难以拓展。
后端有多个服务,要对每个应用和服务进行认证和授权,Token更加方便。
用一个认证服务做这件事
Token特点
优点
- 服务端不用存储token,只需签发和校验token即可
- 跨站点:只要服务端算法一致,token就可以跨站点登录
- 多端可用:移动端开发使用Cookie非常麻烦,使用token非常常见
缺点
- 每个服务都需要实现一点认证授权的业务逻辑,没办法专注于本身业务。
认证授权分散在微服务中,一方面会带来不规范容易出错的问题,另一方面也有潜在的安全风险,开发人员可能会忽略令牌。
JWT
使用Cookie和Session拓展性不好
JWT介绍
JWT(JSON Web Token),JWT本身也是Token,是一种规范化之后的JSON结构的Token
JWT自身包含了身份验证需要的所有信息。因此,我们并不需要额外的存储信息,增加了系统的可用性和伸缩性,大大减轻了服务端的压力。
JWT更适用于安全不敏感的场景,实现多端登录。
JWT流程机制
- 用户向服务器发起请求
- 如果用户名密码校验正确,服务端返回token字符串
- 之后每次访问都加上这个JWT
- 服务端检查JWT并从中获取相关信息
JWT组成部分
JWT本质上是一组字符串,通过“.”切分为三个Base64编码的部分。
- Header : 描述 JWT 的元数据,定义了生成签名的算法以及
Token的类型。
-
Payload : 用来存放实际需要传递的数据
- Payload 部分默认是不加密的,一定不要将隐私信息存放在 Payload 当中
- Signature(签名) :服务器通过 Payload、Header 和一个密钥(Secret)使用 Header 里面指定的签名算法(默认是 HMAC SHA256)生成。
JWT特点
优点:
- 保证信息的可依赖性和不可篡改性
密钥一定保管好,一定不要泄露出去。JWT 安全的核心在于签名,签名安全的核心在密钥
缺点:
- 不安全:跨站请求伪造
请求服务端并携带 JWT 的常见做法是将其放在 HTTP Header 的 Authorization 字段中(Authorization: Bearer Token)
如何加强JWT安全性?
- 更安全的加密算法
- 隐私信息不能放在Payload中
- 保管好密钥
- 加入过期时间,过期时间不宜过长
-
使用成熟的开源库
如何防止JWT被篡改?
有签名的存在,即使JWT泄露或者被截获也可以保证安全。
JWT通常由两种认证流程
- HMAC流程
这种方法认证服务与使用服务两边要协商好secret。因为最终会利用密钥生成Signature进行比较。
- 用户输入信息到认证服务
- 认证服务办法JWT令牌
- 发起请求时携带JWT,然后再资源服务器中进行校验
- 最后返回处理响应
- RSA流程
RSA利用了公私钥签名流程,安全性相对来说高一点,因为保证私钥不泄露即可。
流程与上述相同,区别就是校验方法不同,一个是secret,一个是公私钥。