session和token认证方式,cookie和localStorage存储,Web安全 ——总结
目录
1.web服务的安全问题
1.1 XSS
1.2 CSRF
1.3 同源策略
1.4 跨域访问
1.4 cookie的安全性
2.认证方式
2.1 token和session,两种认证方式
2.2 存token的解决方案
1.web服务的安全问题
1.1 XSS
Cross Site Scripting, 简称XSS (跨站脚本攻击)。
参考:百度百科
解释: XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。 这些恶意网页程序通常是JavaScript,但实际上也可以包括Java、 VBScript、ActiveX、 Flash 或者甚至是普通的HTML。攻击成功后,攻击者可能得到包括但不限于更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。
原理: HTML是一种超文本标记语言,通过将一些字符特殊地对待来区别文本和标记,例如,小于符号(<)被看作是HTML标签的开始,
我的总结:
使用httpOnly的cookie 可以避免cookie受到XSS攻击,而没有使用httpOnly的cookie和Web Storage则容易受到XSS攻击。使用了httpOnly的cookie是js无法访问控制的(document.cookie是获取不到的),而Web Storage(例如localStorage)是可以被js访问控制的,所以从这一点来看cookie相较于Web Storage更加安全。
1.2 CSRF
Cross-site request forgery, 简称CSRF或XSRF (跨站请求伪造)。
参考:百度百科,[写bug博客]https://segmentfault.com/a/1190000015597029
解释:CSRF 是一种挟制用户在当前已登录的Web应用上执行非本意的操作的攻击方法。跟XSS相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对浏览器的信任
原理:我们都知道,当我们访问一个网站或向它发出请求时,浏览器会自动携带cookie,假如cookie中保存了登录状态信息,请看下面的例子:
1.你登录了A银行网站,用一个账号名称为Jacy的账号进行了转账操作,URL是:http://www.examplebank.com/withdraw?account=Jacy&amount=1000&for=SomeBody
2.在你还未退出A银行网站,即保存在cookie中的登录信息有效情况下,你访问了B网站,若这个B网站放入了恶意js代码:http://www.examplebank.com/withdraw?account=Jacy&amount=1000&for=Badman。 B网站在你浏览网站时在背后发送了这个请求,此时浏览器会把带有A网站登录信息的cookie发送给A银行系统,A银行系统会判断cookie认为你是登录/认证的用户,就会执行转账操作,那么你的Jacy账号将损失1000元。
我的总结:
从CSRF来看,cookie是不安全的,但现在浏览器都具备同源策略,所以这种跨域的请求就会被拒绝。若使用token认证技术并将token存在localStorage中,每次请求时从localStorage中取出token放在请求头中,则可以有效避免CSRF。所以从这一点来看localStorage的策略比cookie更安全
1.3同源策略
站点A的域名:www.aaa.com,站点B的域名:www.bbb.com。
假设前端网页是部署在A上,服务端是部署在站点B上。 现在我要从A用ajax给B发请求,这个时候B会拒绝A的请求,这个就是浏览器的同源策略。同源策略是一种保护机制,保护用户不受CSRF攻击。
那么问题来了,假如我的项目时前后端分离,那么我该怎么部署或者说怎么消除同源策略的限制?请看下面的跨域访问
1.4.跨域访问
方案一:Nginx 反向代理
这个可以参考我的另一篇博客:[待完成]
方案二:服务端设置跨域
参考博客:
[阮一峰CORS] https://www.ruanyifeng.com/blog/2016/04/cors.html
[如何设置Access-Control-Allow-Origin] https://www.jianshu.com/p/89a377c52b48
服务端设置响应头:
Access-Control-Allow-Origin: http://example.com
Access-Control-Allow-Credentials: true
前端ajax设置请求头:withCredentials : true
1.5关于cookie的安全性
参考文章
[cookie详解]https://zh.javascript.info/cookie
[同源策略、跨域和cookie的安全性]https://segmentfault.com/a/1190000015597029
2.认证方式
2.1.token和session,两种认证方式
1) session认证
后端操作cookie和session, 采用session认证技术
2)token之jwt技术
JSON Web Token (JWT)是一个开放标准(RFC 7519),简单讲jwt是一项技术规范,遵循这个规范可以生成一个token,token本质就是一串字符,例如:
这是一个很长的字符串,中间有.
隔开,表示token是由3部分组成。(注:token字符串是不换行的,上述例子仅为了方面展示才换行显示)
这个token包含了用户的登录信息(包含用户id等,注:敏感信息是非常不建议放token里的)。客户端登录后就能拿到token,之后需要认证的请求都可以带上token发请求,服务端拿到带token的请求后验证token的正确性并判断是哪个用户。session技术是将登录信息放在服务端(服务端有状态),而token技术是将登录信息放在客户端(也就是服务端是无状态的)。
关于jwt详细分析,可以参考阮老师的博客 https://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html
我认为相较于session认证,token技术的优缺点:
优点:
- 跨域,cookie不支持跨域,token是跨域的。假若你是做公共API的,凡是在你这认证了的网站都分给他们一个token,通过这个token来跨域访问你的API
- 传统的session方案是不支持单点登录的,而token技术可以轻松实现单点登录。
- 更适应移动端,移动端不支持cookie。
- 解耦,token可以在任何地方生成,调用API时生成token即可
缺点:
- 因为需要验证token所以开销更大,占CPU资源;
- 因为token比SessionID要大,所以更占带宽,会消耗更多流量。
- 服务端不能直接让token失效,即在用户退出后,服务端不能让他的token失效,而是要等到token到期后自动失效。要解决这个问题除非增加服务端逻辑,比如设置token黑名单。
下面的问题值得讨论:客户端的token存哪里?
1.用localStorage存token
- 前端登录要存token,退出后要清除token,就是说需要手动存删token,增加了维护的负担
- localStorage存token存在XSS攻击风险
2.用cookie存token
如果是前端自己手动将cookie存token,那么问题和上面用localStorage是一样的。但是,如果是将cookie交给服务端管理,前端不能操作cookie,那么会更加安全。
2.3.存token的解决方案
参考博客:
http://blog.itpub.net/10742815/viewspace-2142725/
https://segmentfault.com/q/1010000022581000
在Web服务应用中,后端通过Set-cookie把token放在cookie中,对cookie设置httpOnly(使js不能访问cookie)。这样做也就是把token交给服务端维护,前端不用管。
我的观点:
一个完善的后端,包含了对Web网页和APP应用提供API,此时后端应该把token放在两处,当用户登录成功后,一方面通过Set-cookie设置token(供Web网页使用),另一方面在返回的json数据中放置token字段(供APP应用使用)。
1)Web服务可以采用上述的方案。
2)但在APP中则有些不同:对APP来说用户的登录状态维持时间应该更长,此时需要两个token,一个是认证用的auth_token,另一个是刷新token的refresh_token (名字不是固定的,表意即可)
APP把两个token保存在本地,每次请求需要取auth_token放置到请求头,当token失效时APP需要取refresh_token去刷新从而获得新的auth_token。其中refresh_token的有效期要比auth_token长,假设auth_token有效期是7天,则可以将refresh_token的有效期设置为14天(token的有效期也不易过长)。