web登录方式
为什么会有登陆态
因为http协议无状态,两次请求服务器无法分辨是否为同一账号请求。登录就是用某种方法让服务器识别不同的请求都是谁发出的。
从登录到登出的过程中,服务器维护了一个可以识别用户信息的数据结构,广义上来说,这个过程叫session,就是保持了一个会话
区别于狭义的session,狭义session指的是登录成功后服务端存储的用户信息
服务端session和客户端sessionId 存储于cookie的方式
过程:
- 客户端带着用户名和密码去访问 /login 接口,服务器端收到后校验正确就会在服务器端存储一个sessionId和session的映射关系
- 服务器端返回response,并且将sessionId以set-cookie的方式种在客户端
- 客户端发起非登录请求时,服务端通过cookie中的sessionId找到对应的session来知道此次请求是谁发出的。
将sessionId存在cookie并不是一种强制的方案,而是大家一般都这么做,而且发请求的时候符合domain和path的时候,会自动带上cookie,省去了手动塞的过程。
token / jwt 方式
两者区别:
- sessionId的方式本质是把用户状态信息维护在server端,cookie传输。虽然方便但有安全问题。
- token的方式把用户信息生成一串token传给前端,前端每次发请求时带上token,传回给服务器端;服务器端收到请求之后,解析token并且验证相关信息;
- 最本质的区别是通过解析token的计算时间换取了session的存储空间
以jwt(json web token)为例:
主要由三部分组成
header 头部 描述签名算法和token的类型,类型一般都是JWT
{
"alg": "HS256",
"typ": "JWT"
}
payload 负载 用户信息
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022,
"exp": 1555341649998
}
signature 签名 对前两部分的签名,实现需要一个密钥(secret)这个secret只有服务器才知道,然后使用header里面的算法按照如下方法来签名:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
最后的 jwt = base64url(header) + "." + base64url(payload) + "." + signature
jwt可以放在response中返回,也可以放在cookie中返回。客户端发起请求时,官方推荐放在HTTP header中:
Authorization: Bearer
存在的问题
- session需要存储,多机存储和用户量增多时,对存储空间有要求
- session+cookie里面存sessionId的方式可能会有csrf攻击的问题,常见的方式是使用csrf_token来解决
- jwt的过期时间需要结合业务做设置,而且jwt一旦派发出去,后端无法强行使其作废
跨页面登陆态同步方法
单点登录(Single Sign On),简称为 SSO.
定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。
同域下的单点登录
一个企业一般情况下只有一个域名,通过二级域名区分不同的系统。比如我们有个域名叫做:a.com,同时有两个业务系统分别为:app1.a.com和app2.a.com。我们要做单点登录(SSO),需要一个登录系统,叫做:sso.a.com。
问题一:在sso.a.com登陆后,因为cookie不能跨域,所以无法在app1.a.com和app2.a.com这两个域名发送请求时携带cookie
解决方法:sso登录以后,可以将Cookie的域设置为顶域,即.a.com,这样所有子域的系统都可以访问到顶域的Cookie。
问题二:sso、app1和app2是不同的应用,它们的session存在自己的应用内,是不共享的
解决办法:把3个系统的Session共享。共享Session的解决方案有很多,例如:Spring-Session。
不同域下的单点登录
说到单点登录,就肯定会见到这个名词:CAS (Central Authentication Service)
上图是CAS官网上的标准流程,具体流程如下:
- 用户访问app系统,app系统是需要登录的,但用户现在没有登录。
- 跳转到CAS server,即SSO登录系统,以后图中的CAS Server我们统一叫做SSO系统。 SSO系统也没有登录,弹出用户登录页。
- 用户填写用户名、密码,SSO系统进行认证后,将登录状态写入SSO的session,浏览器(Browser)中写入SSO域下的Cookie。
- SSO系统登录完成后会生成一个ST(Service Ticket),然后跳转到app系统,同时将ST作为参数传递给app系统。
- app系统拿到ST后,从后台向SSO发送请求,验证ST是否有效。
- 验证通过后,app系统将登录状态写入session并设置app域下的Cookie。
app1登陆后访问app2的流程
- 用户访问app2系统,app2系统没有登录,跳转到SSO。
- 由于SSO已经登录了,不需要重新登录认证。
- SSO生成ST,浏览器跳转到app2系统,并将ST作为参数传递给app2。
- app2拿到ST,后台访问SSO,验证ST是否有效。
- 验证成功后,app2将登录状态写入session,并在app2域下写入Cookie。
业务系统拿ST再次访问SSO进行验证,这个步骤是为了保证安全。如果业务系统不确认一下这个用户收否是伪造的,那直接在浏览器中敲入回调地址带上用户信息即可登录。
cookie相关知识点及安全性问题
是什么,存在哪儿,怎么传输
Cookie既指整个状态保存机制,也指用户保存状态的数据本身,由String类型的name和value以及若干属性组成。
Cookie由服务端生成,保存在浏览器。通过两个Http Header:Set-Cookie和Cookie进行传输。
很多浏览器会提供读Cookie和写Cookie的api给运行在其上Javascript脚本使用,通常的api是操作docment.cookie:
document.cookie=“SID=31d4d; domain=example.com; path=/;”;
关键属性和不同类型的cookie
Domain、Path、Name三者唯一确定一个cookie。
其它属性仅用作读写时的权限控制,不作为cookie标识。
Domain
和 Path
标识定义了Cookie的作用域:即Cookie应该发送给哪些URL。
Domain
标识指定了哪些主机可以接受Cookie。如果不指定,默认为当前文档的主机(不包含子域名)。如果指定了Domain
,则一般包含子域名。
例如,如果设置 Domain=mozilla.org
,则Cookie也包含在子域名中(如developer.mozilla.org
)。
Path
标识指定了主机下的哪些路径可以接受Cookie(该URL路径必须存在于请求URL中)。以字符 %x2F
("/") 作为路径分隔符,子路径也会被匹配。
例如,设置 Path=/docs
,则以下地址都会匹配:
/docs
/docs/Web/
/docs/Web/HTTP
domain向上通配,path向下通配
cookie分为会话期cookie和持久性cookie
会话期Cookie:浏览器关闭之后会被自动删除,仅在会话期内有效。不需要指定过期时间(Expires
)或者有效期(Max-Age)。
持久性Cookie:可以指定一个特定的过期时间(Expires
)或有效期(Max-Age
)。
Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;
提示:当Cookie的过期时间被设定时,设定的日期和时间只与客户端相关,而不是服务端。
需要注意的是,有些浏览器提供了会话恢复功能,这种情况下即使关闭了浏览器,会话期Cookie也会被保留下来,就好像浏览器从来没有关闭一样。
Cookie的有效期过长可能导致通行证泄露。比如用户使用了公用电脑,关闭浏览器时,没有点击注销。这样Cookie就留存在这台电脑上,其它人只需打开浏览器即可获取其在网站上的cookie。
一般保存通行证的cookie应该设置为session有效的cookie,并在用户选择记住登录状态时,提醒用户,不要再公用电脑上做这样的勾选。
安全问题
明文传输的HTTP流量
HTTP明文传输数据的特性,使得攻击者可从网路上抓包获取Cookie。
解决方案:
- 服务端使用HTTPS
- 指定cookie的secure属性,该属性使cookie只能在HTTPS请求中带出。
利用XSS漏洞读取保存在cookie的通行证
假如网站存在XSS漏洞,那么恶意JS可直接读取Cookie中的通行证。可以通过指定Cookie的HttpOnly属性。对于指定了HttpOnly的Cookie,浏览器会拒绝JS读写。
XSS仍有可能利用服务端漏洞获取cookie: - 服务端有可能在请求的正常响应中包含通行证。不要笑,这真的有,尤其现在很多公司app和web共用一套后台; - 服务端可能有漏洞导致cookie包含在请求响应中,从而被窃取。比如:Apache CEV-2012-005
所以HttpOnly不是银弹,XSS也有很多其它的危害。但至少,HttpOnly可以避免通行证在浏览器被JS直接读取。
跨站请求伪造(CSRF)
比如在不安全聊天室或论坛上的一张图片,它实际上是一个给你银行服务器发送提现的请求:
当你打开含有了这张图片的HTML页面时,如果你之前已经登录了你的银行帐号并且Cookie仍然有效(还没有其它验证步骤),你银行里的钱很可能会被自动转走。有一些方法可以阻止此类事件的发生:
- 设置Cookie的SameSite属性。该属性规定cookie只会在当前正在访问(浏览器地址栏)的域名与cookie的domain可匹配时,才会带出。
- 任何敏感操作都需要确认;
- 用于敏感信息的Cookie只能拥有较短的生命周期;
- 更多方法可以查看OWASP CSRF prevention cheat sheet_Prevention_Cheat_Sheet)。
参考资料: