跨域SSO单点登录授权,看这一篇就够了,没有漏洞的安全身份验证

前言

1.最近公司做的系统增加了不少,需要考虑用户的登录问题,于是在网上了解了一番SSO,好像大部分都写得有问题,比如说所有子系统都用同一个sso生成的令牌ID,不谈ID是否加密的,加密还好,明文的不就完蛋了吗,要知道子系统通过这个ID换取最终的子系统中要使用的用户ID或信息,该操作是子系统通过web请求sso来实现的,不是从浏览器发出的,而是在系统的服务上发出的请求,莫非sso里面要做IP请求限制吗?不处理的话任何人拿到这个令牌ID不都可以直接进入子系统了吗?(此处不要犯迷糊,说什么其他人又没有登录SSO没有cookie或者session,说这个有什么用呢?还是说请求是从服务器通过webrequest请求的SSO,莫非服务器上有保存的cookie,还是说你很牛逼,能跨域读取cookie)

2.还有说什么维护一个子系统的列表通过轮循的方式给系统发请求然后写cookie,先不说安全,我想说要是有100个系统接入使用这一个sso,用户想用其中的一个,你也要轮循100次啊,那用户可以洗洗睡了用户用的正好是第一百个,等你轮循过来,用户都睡醒一觉了,再说安全方面,sso能给你发请求,其他人就不能往你这个地址发请求吗?要知道sso主动给子系统发请求,和sso通知子系统让子系统来请求sso是不一样的,虽然可以加密或者校验,何必呢,这不是自己给自己找事做吗.

3.还有说什么注销的,不知道有没有搞清楚sso的意图,是单点登录,或者说是授权用户能够通过验证后使用最终的产品,只要用户验证通过,sso就和子系统之间没有关系了,说白一点,SSO就是只负责用户能够进入房间的一道门,至于你进去做什么,什么时候出来,从哪里出来SSO都管不了,有时候sso保存的cookie或者session到期了,子系统是照样可以用的,因为子系统已经被授权可以使用了,但如果退出子系统想再次登录就需要再次输入账号密码了.举例说明:用户登录sso成功后cooike或者session有效期1个小时,用户成功进入了子系统,然后子系统里面使用cookie保存用户的ID等信息有效期1天,那用户只要是用这个浏览器登录这个子系统一天内都不需要登录账号密码,即便是sso的登录已经超时.

我们要达到的目的:

1.不给服务器增加额外的负担,比如说轮循等,用户用哪个系统sso就处理哪个系统.

2.只让用户输入一次账号密码就能用多个系统

3.保证信息安全

言归正传,开始说SSO,和开发语言无关

准备事项

SSO系统地址:sso.com,登录界面地址:/login,授权地址:/auth,通过令牌获取用户信息的地址:/getuser

二个子系统:    a.com(a系统),   b.com(b系统)

子系统回调页面地址统一是:/ssocallback,当然可以每个系统单独配置,用配置文件存,或者用数据库存都可以.

最终的所有系统的地址共有:

sso.com/login:负责用户登录账号密码

sso.com/auth:负责子系统登录时的授权许可

sso.com/getuser:子系统通过令牌请求的用户信息的地址

a.com/ssocallback:授权成功后sso要跳转到的地址

b.com/ssocallback:授权成功后sso要跳转到的地址

所用到的术语

tokenID:临时令牌,用于SSO通知a.com和b.com来通过此ID获取用户真实信息,此ID有时效性,并只允许使用一次,且保证唯一性,可以用GUID,该ID需要加密传输,密匙(公匙/私匙)千万要保密,由SSO和a.com/b.com各自保存好,且a.com/b.com要使用不一样的密匙,可以通过配置文件保存或者数据库保存

20秒:tokenID的有效时长,即:a或b系统通过tokenID请求真实用户信息的有效期,太长了不安全,如果有用户拿到tokenID,并解密了这个tokenID,自己伪造请求sso.com/getuser就能获取用户的一些信息了.为了安全密匙要经常换一下,tokenID要加时间戳或随机数来加密生成,最终目的就是为了保证安全不被破解,甚至也可以采用动态同步密匙+签名等一些途径,此处自己解决.

用户登录:是指在sso系统中用户输入账号密码的登录

用户授权:是指用户在a.com/b.com是否有使用权限

appID:是标识a.com和b.com的一个ID,每个系统不一样,且该ID须保证唯一性,案例中使用(appID.a标识a.com),(appID.b标识b.com)

程序中cookie或session的判断(案例中选择使用cookie)

sso系统中:除了/login页面外其他页面需要验证用户登录cookie,没有登录则跳转到/login页面

a和b系统中:除了/ssocallback页面外其他页面需要验证用户授权cookie,没有授权则跳转到sso.com/auth页面

开始解说

情况一:用户第一次使用a.com系统

[手动]用户打开a.com系统       此时没有用户授权cookie,携带appID.a参数      》[自动]跳转到sso.com/auth页面       此时没有用户登录cookie,携带appID.a参数      》[自动]跳转到sso.com/login页面提示用户输入账号密码登录成功       写入用户登录cookie(1小时),携带appID.a参数      》[自动]跳转到sso.com/auth,auth页面显示一些信息:你确定要授权登录a.com系统吗? 点击:[确定]生成一个tokenID存入cache里面,并设定有效期20秒       携带tokenID参数      》[自动]跳转到a.com/ssocallback,程序要获取这个tokenID,然后通过http附带tokenID参数请求sso.com/getuser,getuser页面得到tokenID,验证tokenID有没有超出20秒过期,过期的话需要跳转到/auth重新确认授权,如果没有过期则返回用户的ID等信息,并将此tokenID废弃,不允许此tokenID再次使用,此时a.com/ssocallback的程序得到响应即:用户的ID等信息,将此信息写入cookie,             》[自动]跳转到a.com系统的首页

情况二:用户直接打开b.com系统

[手动]用户打开b.com系统       此时没有用户授权cookie,携带appID.b参数      》[自动]跳转到sso.com/auth页面,此时已经有用户登录的cookie了,auth页面显示一些信息:你确定要授权登录b.com系统吗? 点击:[确定]生成一个tokenID存入cache里面,并设定有效期20秒       携带tokenID参数      》[自动]跳转到b.com/ssocallback,程序要获取这个tokenID,然后通过http附带tokenID参数请求sso.com/getuser,getuser页面得到tokenID,验证tokenID有没有超出20秒过期,过期的话需要跳转到/auth重新确认授权,如果没有过期则返回用户的ID等信息,并将此tokenID废弃,不允许此tokenID再次使用,此时b.com/ssocallback的程序得到响应即:用户的ID等信息,将此信息写入cookie,             》[自动]跳转到a.com系统的首页

PS:sso.com/auth页面放一个按钮让用户点击也可以,不放按钮,页面直接处理验证并自动跳转也可以.这个页面就是sso的核心,所有的系统都要经过这个页面来验证通过后才可以.

上述过程即可实现SSO单点登录功能,这样每个业务系统或者应用系统就不用考虑用户登录的事情了,系统最好之后接入sso就可以了,且没有太复杂的逻辑,并能保证安全性,用户只要登录一次就能保证各个系统之间切换,只要浏览器不关闭所有系统都经过一次sso.com/auth的一次授权就行,如果浏览器关闭,使用session方式的话,需要再次通过auth授权,使用cookie的话如果授权cookie不过期就不需要再次授权了.

对于注销问题,sso系统提供退出登录功能,a.com和b.com提供退出系统和注销用户,sso的退出登录则是清空sso的cookie,再有系统登陆的话就需要输入账号密码来登录了,a.com和b.com的退出系统是清空各自系统的cookie,如果在想进入系统的话,只要sso的cookie不过期就不需要重新输入账号密码,a.com和b.com的的注销用户则是通知sso系统清空用户登录的cookie,同sso的退出登录功能一样.但没法保证a.com注销后页同时注销b.com的登录,有人说可以让a.com通知sso,让sso通知b.com注销,那要是一万个站点接入sso,sso要通知这一万吗,同步的话用户可以洗洗睡了,异步的话用户一关闭页面就停止了,达不到效果,还有人说,用户授权登录过哪几个系统只保存这几个系统的列表就行了,那我想说,有一万个用户登录并授权,你要维护一万个用户的系统列表吗,一万的用户规模不算大,十万个用户,百万个用户呢,那你的sso服务器得杠杠的才行,要不扛不住用户规模.当然如果真需要注销也是可以做的,不管是按用户来维护系统列表,还是维护一个全局的所有系统列表,最主要的是保证接入的系统要真实的处理注销操作,而不是挂个空地址,如果接入的系统都是自己公司开发的还好,如果第三方,他们挂个空地址糊弄一下你也没办法,最终的结果就是还是没有清除掉session或者cookie,注销操作的做法,a.com要注销,然后通知sso系统,由sso系统发起所有的注销请求,将所有的系统拼接成一个参数,由sso先发往a1.com,然后a1.com注销成功后从参数中找到自己并排除掉然后找到下一个系统的地址a2,将剩余参数传递给a2.com,a2.com注销成功后从参数中找到自己并排除掉然后找到下一个系统的地址a3,将剩余参数传递给a3.com依次处理,不能用ajax,因为是服务器之间发起请求,不会也不能经过客户浏览器,并且从sso发起的注销请求中不止包含系统列表参数,还得包含被注销的用户参数,每个系统获取到用户参数后就执行清理该用户的cookie和session的操作,如果有一万个系统,a是第一个,b是最后一个,当a注销完之后,b可能不会立即超时,等到注销请求发到b的时候,b才能超时.方法有很多,但是需要保证不会被糊弄.

会出现的正常情况

1.用户正常使用着a.com,然后新选卡要打开b.com的时候需要sso输入账号密码登录

这是因为b.com的cookie或者session已经过期,但是a.com之前就已经授权成功了,用户没有关闭浏览器(或选项卡),a.com的cookie或者session没过期,但是sso系统的cookie已经过期了,所以使用b.com的时候需要sso重新登录账号来验证并授权.

2.同一个浏览器同时打开着a.com和b.com但a和b里面登录的用户却不是同一个用户

这是因为用户授权a.com成功后,用户使用另一个用户登录sso,然后又打开b.com,所以a.com使用的是老的用户,而b.com使用的新登录sso系统的用户,但如果关闭a.com的浏览器或者选项卡,或者让a.com退出登录(即:最终目的就是清除a.com的cookie和session)让a.com重新去sso.com/auth验证授权即可让a.com也使用新用户.

 

题外话:OAuth和SSO原理不是一回事,但也差不多,SSO是为了解决多系统用户登录多次的情况,Oauth是为了解决用户在一个系统里面要使用另一个系统里面的东西(如:数据,文件,接口等),SSO系统三类对象:人,sso授权系统,业务系统(或者叫应用系统),Oauth则是相当于把sso系统的人这个对象转换成另外一个受限的应用系统,由授权系统授权业务系统(或应用系统)来有权限的访问或操作受限的系统.

方式二:

sso验证用户通过后,主动post发送公匙加密后的用户信息给子系统,加密的用户信息中包含一个accesstoken,然后子系统获取用户信息后私匙解密并写入缓存,并且用私匙将accesstoken加密并返回响应给sso,sso获取到签名后的accesstoken后用公匙验证签名通过后,携带签名的accesstoken跳转回子系统,子系统根据accesstoken取出缓存的用户信息写入cookie或者session,并将该缓存删除,避免再次使用.

本人才疏学浅,也不知道说的东西对不对,但感觉上面说的东西还是能在保证安全的情况下实现用户的单点登录问题,如有问题欢迎大家指点指正.

你可能感兴趣的:(用户验证)