马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
弁言:
单点登录的英文名叫做:Single Sign On(简称SSO)。
指在同一帐号平台下的多个应用系统中,用户只需登录一次,即可访问全部相互信任的系统,实现多个系统,统一登陆。
本文重要介绍了常见单点登录流程,并对三种登录授权方式原理做了分析比较:cookie,cas,oauth2。
可以将单点登录简单分为:同根域单点登录、不同根域下单点登录。
一、同根域Cookie登录
Cookie和Session是相对的概念,都是基于key-value布局存储数据,不同是一个用在客户端一个用在服务端。
Cookie可以应用在很多场景,如一些内网后台管理系统、Portal门户、SSO统一登录、追踪用户的身份、根据特定用户进行推送或推荐等…
默认环境下,Cookie只能在同一域名下使用,通过设置domain为根域名,则Cookie可以实现同根域下共享,同根域名下基于cookie就可以方便实现SSO登录;在某些约束下,也可以实现跨域的cookie共享。
1.1 同根域下单点登录:
一般一个企业只会有一个主域名,通过二级域名区分子系统。举个例子:一个企业中有三个子系统(app1.domain.com、app2.domain.com、sso.domain.com),根域名同为domain.com。
登录过程:登录sso.domain.com后,通过http response写入cookie信息,包含了登录的sessionId等信息,domain设置为根域 domain.com;用户访问app1和app2时服务器就可以获取到sessionId,验证用户为登录状态,用户在浏览器上就可以正常获取app1和app2的资源。
简单易用缺点也比较显着:
cookie中如果存放了用户的敏感信息,一旦被窃取(用户的Cookie大概会由于网站的XSS漏洞而被盗取),这个负面影响大。
如果大量的用户信息放入cookie,对浏览器端压力较大,同时cookie存储的信息量大小有限不够轻量级,跨域环境下将会带来一定的麻烦。
1.2 cookie共享代码实例
搭建了基于SpringBoot的HTTPS服务,使用keytools生成了证书,SSL配置:
- server:
- port: 9043
- ssl:
- key-store: classpath:ssLserver.jks
- key-store-password: '@lmggTy6XNZmJwu7'
- key-store-type: JKS
复制代码
注:为了消除浏览器安全提示,必要将证书导入信任证书列表中。
并修改host文件,配置域名映射,均指向本机,类似:
- 127.0.0.1 app1.domain.com
- 127.0.0.1 app2.domain.com
复制代码
关于Cookie共享的代码验证,分5个场景:
(1) 设置默认cookie
请求: https://app1.domain.com:9043/setDefaultCookie?name=defaultCk&value=ckValue
- ResponseCookie cookie = ResponseCookie.from(name, value)
- .httpOnly(true)//httpOnly 防止XSS漏洞js读取cookie
- .secure(true)
- .path("/")
- .maxAge(3600)
- .build();
- response.setHeader(HttpHeaders.SET_COOKIE, cookie.toString());
复制代码
(2) 设置根域名cookie: domain.com
请求:https://app1.domain.com:9043/setRootCookie?name=rootCk&value=rtCkValue
- ResponseCookie cookie = ResponseCookie.from(name, value)
- .httpOnly(true)
- .secure(true)
- .domain("domain.com")
- .path("/")
- .maxAge(3600)
- .build();
- response.setHeader(HttpHeaders.SET_COOKIE, cookie.toString());
复制代码
访问https://app2.domain.com:9043/printCookie 可发送根域名的cookie
(3) 不同子域名cookie:app2.domain.com ✘
请求:https://app1.domain.com:9043/setOtherDomainSameRootCookie?name=sameRoot&value=Val
- ResponseCookie cookie = ResponseCookie.from(name, value)
- .httpOnly(true)
- .secure(true)
- .domain("app2.domain.com")
- .path("/")
- .maxAge(3600)
- .build();
- response.setHeader(HttpHeaders.SET_COOKIE, cookie.toString());
复制代码
(4) 设置不同根域名cookie: app1.host.com ✘
请求:https://app1.domain.com:9043/setOtherDomainDiffRootCookie?name=diffRoot&value=val
(5) 设置跨域共享cookie: app1.host.com
请求:https://app1.domain.com:9043/setNoneSameSite?name=noneSameSiteCk&value=val
- ResponseCookie cookie = ResponseCookie.from(name, value)
- .httpOnly(true)
- .secure(true)
- .path("/")
- .maxAge(3600)
- .sameSite("None")
- .build();
- response.setHeader(HttpHeaders.SET_COOKIE, cookie.toString());
复制代码
跨域获取:https://app2.domain.com:9043/printCookie 是无法获取cookie的。现实上完整描述应该是“跨域请求获取”。
跨域请求获取又可以细分为:基于Form的表单请求、Ajax跨域请求
Form表单跨域请求:
某高仿APP1提供了一个页面https://app1.host.com:9043/indexPage 如下:
- <form id="fm_crossDomainForm" method="post">
- </form>
- Form提交
复制代码
用户访问后就会将第(5)种cookie提交上去,这就是一种CSRF攻击。
可以接纳以下措施防范防范措施:
✓ 搭建HTTPS协议安全网站,cookie不要设置为 sameSite:none
✓ 短信验证码
注:sameSite: https://blog.csdn.net/qq_36690992/article/details/117965822
Ajax跨域请求:CORS
跨域请求服务端必要在响应头添加
- response.setHeader("Access-Control-Allow-Origin", request.getHeader("origin"));
复制代码
浏览器Ajax跨域请求
- $.ajax({
- url: "https://app1.domain.com:9043/printCookie",
- contentType: 'application/x-www-form-urlencoded',
- type: 'POST',
- async: false,
- xhrFields: {
- withCredentials: true
- },
- success: function (result) {
- console.log(result);;
- },
- error: function (data) {
- console.log(data);
- }
- });
复制代码
Ajax请求默认是不会传任何cookie的。加上代码第6、7行参数配置,才开启了浏览器上传cookie,同时服务端配置响应头
- response.setHeader("Access-Control-Allow-Credentials", "true");
复制代码
参考:https://blog.csdn.net/qq_33479841/article/details/123364237
二、不同根域下CAS单点登录
基于浏览器的安全机制, 不同的域名之间无法实现cookie共享。针对这种环境要实现单点登录,必要借鉴CAS(Central Authentication Service)的设计思想。CAS的设计思路重要如下图所示:
[img=604.7333333333333,280.07601049868765]https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pbWcyMDI0LmNuYmxvZ3MuY29tL2Jsb2cvMjk3NzI1LzIwMjYwOC8yOTc3MjUtMjAyNjA4MTQxNjA2NTI1OTAtMTQ4Nzc0ODM1Ny5wbmc=[/img]
[img=604.7333333333333,993.1393175853019]https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pbWcyMDI0LmNuYmxvZ3MuY29tL2Jsb2cvMjk3NzI1LzIwMjYwOC8yOTc3MjUtMjAyNjA4MTQxNjA2NTM0MTItNTMxMDY4MjkucG5n[/img]
图 CAS时序图 https://apereo.github.io/cas/6.6.x/protocol/CAS-Protocol.html
示例:阿里云sso路径
- https://login.alibaba-inc.com/ssoLogin.htm?
- BACK_URL=https%3A%2F%2Fmail.alibaba-inc.com%2Falimail%2F
- &preLoginKey=gQksImpGUd1666162247475pCPJHRnhCV
- &CONTEXT_PATH=%2Falimail%2F
- &APP_NAME=webmail
复制代码
三、基于oauth2的认证
Oauth2是一种授权框架/协议,用来授权给第三方应用,获取用户数据(在不知道用户名、密码的前提下)。用于APP或网页应用微信登录、 QQ 登录、微博登录。第三方网站上授权获得用户信息之后,进行绑定等操作。
OAuth2.0 协议的授权流程可以参考下面的流程图,共四个角色,其中 Client 指第三方应用,Resource Owner 指用户,Authorization Server 是开放平台的授权服务器,Resource Server 是开放平台的 API 服务器(用户数据)。
[img=604.733,317.504]https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pbWcyMDI0LmNuYmxvZ3MuY29tL2Jsb2cvMjk3NzI1LzIwMjYwOC8yOTc3MjUtMjAyNjA4MTQxNjA2NTI0NTktMTI3NjY3MzM4OS5wbmc=[/img]
图 抽象协议流
[img=604.733,561.479]https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pbWcyMDI0LmNuYmxvZ3MuY29tL2Jsb2cvMjk3NzI1LzIwMjYwOC8yOTc3MjUtMjAyNjA4MTQxNjA2NTI1ODMtNzk4OTA1NjA0LnBuZw==[/img]
图 获取token及认证过程
强调local state的概念,这个字段是在登录成功后获取Authorization Code时传给AS的,是什么作用呢?
[img=604.733,413.424]https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pbWcyMDI0LmNuYmxvZ3MuY29tL2Jsb2cvMjk3NzI1LzIwMjYwOC8yOTc3MjUtMjAyNjA4MTQxNjA2NTI3NzktNTQ4ODgwNDEucG5n[/img]
以绑定两个账号为例:攻击者A获取自己的Authorization Code,制造跳转毗连到APP服务,用户B在不知情的环境下,在自己浏览器上使用该毗连发起了绑定请求(GET方式),最终绑定了A的账号。
- 要防止这样的攻击其实很容易,作为第三方应用的开发者,只需在OAuth认证过程中加入state参数,并验证它的参数值即可。具体细节如下:
-
- 在将用户重定向到OAuth2的Authorization Endpoint去的时候,为用户生成一个随机的字符串,并作为state参数加入到URL中。
- 在收到OAuth2服务提供者返回的Authorization Code请求的时候,验证接收到的state参数值。如果是正确合法的请求,那么此时接受到的参数值应该和上一步提到的为该用户生成的state参数值完全一致,否则就是异常请求。
- state参数值需要具备下面几个特性:
- 1.不可预测性:足够的随机,使得攻击者难以猜到正确的参数值
- 2.关联性:state参数值和当前用户会话(user session)是相互关联的
- 3.唯一性:每个用户,甚至每次请求生成的state参数值都是唯一的
- 4.时效性:state参数一旦被使用则立即失效
-
- 链接:https://www.jianshu.com/p/c7c8f51713b6
-
复制代码
OAuth考虑了各种Web攻击,比如CSRF (Cross-Site Request Forgery), Clickjacking等,OAuth协议文档中已经有了比较全面的阐述
参考:https://www.rfc-editor.org/rfc/rfc6749
https://www.jianshu.com/p/c7c8f51713b6
四、CAS与OAuth2区别:
● CAS 客户端要获取的最终信息是,这个用户到底有没有权限访问我(CAS 客户端)的资源;
● OAuth2 获取的最终信息是,我(oauth2 服务提供方)的用户的资源到底能不能让你(oauth2 的客户端)访问。 存在资源的转移使用。
● CAS感觉就是把oauth2的Client和RS合并到了一起(很微妙也很关键的区别)。
总结:CAS是"直接认证",OAuth2是"授权访问",前者更简单直接,后者更灵活安全。
思考:
如何登出
附:
实现SSO常见的几个协议:CAS, SAML、OpenID, OAuth2(开放授权)
一些开源框架:
Apereo CAS https://www.apereo.org/projects/cas
keycloak https://www.keycloak.org/
云平台:
阿里云SSO https://help.aliyun.com/document_detail/93684.html
|