Cross-Site Scripting(跨站脚本攻击)简称 XSS,是一种代码注入攻击。攻击者经过在目标网站上注入恶意脚本,使之在用户的浏览器上运行。利用这些恶意脚本,攻击者可获取用户的敏感信息如 Cookie、SessionID 等,进而危害数据安全。php
为了区分CSS,改成XSS。html
XSS 的本质是:恶意代码未通过滤,与网站正常的代码混在一块儿;浏览器没法分辨哪些脚本是可信的,致使恶意脚本被执行。前端
根据攻击的来源,XSS 攻击可分为存储型、反射型和 DOM 型三种。数据库
类型 | 存储区 | 插入点 |
---|---|---|
存储型 XSS | 后端数据库 | HTML |
反射型 XSS | URL | HTML |
DOM 型 XSS | 后端数据库/前端存储/URL | 前端 JavaScript |
存储区:恶意代码存放的位置。后端
插入点:由谁取得恶意代码,并插入到网页上。浏览器
这种攻击常见于带有用户保存数据的网站功能,如论坛发帖、商品评论、用户私信等。安全
反射型 XSS 跟存储型 XSS 的区别是:存储型 XSS 的恶意代码存在数据库里,反射型 XSS 的恶意代码存在 URL 里。bash
反射型 XSS 漏洞常见于经过 URL 传递参数的功能,如网站搜索、跳转等。服务器
因为须要用户主动打开恶意的 URL 才能生效,攻击者每每会结合多种手段诱导用户点击。cookie
POST 的内容也能够触发反射型 XSS,只不过其触发条件比较苛刻(须要构造表单提交页面,并引导用户点击),因此很是少见。
DOM 型 XSS 跟前两种 XSS 的区别:DOM 型 XSS 攻击中,取出和执行恶意代码由浏览器端完成,属于前端 JavaScript 自身的安全漏洞,而其余两种 XSS 都属于服务端的安全漏洞。
输入侧过滤可以在某些状况下解决特定的 XSS 问题,但会引入很大的不肯定性和乱码问题。在防范 XSS 攻击时应避免此类方法。
存储型和反射型 XSS 都是在服务端取出恶意代码后,插入到响应 HTML 里的,攻击者刻意编写的“数据”被内嵌到“代码”中,被浏览器所执行。
预防这两种漏洞,有两种常见作法:
1.改为纯前端渲染,把代码和数据分隔开。
2.对 HTML 作充分转义。
纯前端渲染
1.浏览器先加载一个静态 HTML,此 HTML 中不包含任何跟业务相关的数据。
2.而后浏览器执行 HTML 中的 JavaScript。
3.JavaScript 经过 Ajax 加载业务数据,调用 DOM API 更新到页面上。
在纯前端渲染中,咱们会明确的告诉浏览器:下面要设置的内容是文本(.innerText),仍是属性(.setAttribute),仍是样式(.style)等等。浏览器不会被轻易的被欺骗,执行预期外的代码了。
转义HTML
若是拼接 HTML 是必要的,就须要采用合适的转义库,对 HTML 模板各处插入点进行充分的转义。
经常使用的模板引擎,如 doT.js、ejs、FreeMarker 等,对于 HTML 转义一般只有一个规则,就是把 & < > " ' / 这几个字符转义掉,确实能起到必定的 XSS 防御做用,但并不完善:
XSS 安全漏洞 | 简单转义是否有防御做用 |
---|---|
HTML 标签文字内容 | 有 |
HTML 属性值 | 有 |
CSS 内联样式 | 无 |
内联 JavaScript | 无 |
内联 JSON | 无 |
跳转连接 | 无 |
DOM 型 XSS 攻击,实际上就是网站前端 JavaScript 代码自己不够严谨,把不可信的数据看成代码执行了。
在使用 .innerHTML、.outerHTML、document.write() 时要特别当心,不要把不可信的数据做为 HTML 插到页面上,而应尽可能使用 .textContent、.setAttribute() 等。
若是用 Vue/React 技术栈,而且不使用 v-html/dangerouslySetInnerHTML 功能,就在前端 render 阶段避免 innerHTML、outerHTML 的 XSS 隐患。
DOM 中的内联事件监听器,如 location、onclick、onerror、onload、onmouseover 等, 标签的 href 属性,JavaScript 的 eval()、setTimeout()、setInterval() 等,都能把字符串做为代码运行。若是不可信的数据拼接到字符串中传递给这些 API,很容易产生安全隐患,请务必避免。
禁止加载外域代码,防止复杂的攻击逻辑。
禁止外域提交,网站被攻击后,用户的数据不会泄露到外域。
禁止内联脚本执行(规则较严格,目前发现 GitHub 使用)。
禁止未受权的脚本执行(新特性,Google Map 移动版在使用)。
合理使用上报能够及时发现 XSS,利于尽快修复问题。
复制代码
对于不受信任的输入,都应该限定一个合理的长度。虽然没法彻底防止 XSS 发生,但能够增长 XSS 攻击的难度
HTTP-only Cookie: 禁止 JavaScript 读取某些敏感 Cookie,攻击者完成 XSS 注入后也没法窃取此 Cookie。
验证码:防止脚本冒充用户提交危险操做。
CSRF(Cross-site request forgery)跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕事后台的用户验证,达到冒充用户对被攻击的网站执行某项操做的目的。
<img src="http://bank.example/withdraw?amount=10000&for=hacker" >
复制代码
<form action="http://bank.example/withdraw" method=POST>
<input type="hidden" name="account" value="xiaoming" />
<input type="hidden" name="amount" value="10000" />
<input type="hidden" name="for" value="hacker" />
</form>
<script> document.forms[0].submit(); </script>
复制代码
访问该页面,表单会自动提交。
连接类型的CSRF并不常见,比起其余两种用户打开页面就中招的状况,这种须要用户点击连接才会触发。这种类型一般是在论坛中发布的图片中嵌入恶意连接,或者以广告的形式诱导用户中招,攻击者一般会以比较夸张的词语诱骗用户点击,例如:
<a href="http://test.com/csrf/withdraw.php?amount=1000&for=hacker" taget="_blank">
重磅消息!!
<a/>
复制代码
既然CSRF大多来自第三方网站,那么咱们就直接禁止外域(或者不受信任的域名)对咱们发起请求。
* Origin Header
* Referer Header
复制代码
用户打开页面的时候,服务器给这个用户生成一Token,但不能放到cookie中,不然仍是会被攻击者冒用。因此要存在服务器的session中
大型网站,使用session存储CSRF Token会带来很大压力。并且如今都是分布式部署,一个用户发送的屡次HTTP请求可能不在一台服务器上,可能会获取不到session数据,所以分布式集群中CSRF Token存储在Redis之类的公共存储空间
使用Session存储,读取和验证Token会引发比较大的复杂度和性能问题。
这种方法的Token是一个计算出来的结果,而非随机生成的字符串。这样在校验时无需再去读取存储的Token,只用再次计算一次便可。
那么另外一种防护措施是使用双重提交Cookie。利用CSRF攻击不能获取到用户Cookie的特色,咱们能够要求Ajax和表单请求携带一个Cookie中的值。
优势
无需使用Session,适用面更广,易于实施。
Token储存于客户端中,不会给服务器带来压力。
相对于Token,实施成本更低,能够在先后端统一拦截校验,而不须要一个个接口和页面添加。
缺点
Cookie中增长了额外的字段。
若是有其余漏洞(例如XSS),攻击者能够注入Cookie,那么该防护方式失效。
难以作到子域名的隔离。
为了确保Cookie传输安全,采用这种防护方式的最好确保用整站HTTPS的方式,若是还没切HTTPS的使用这种方式也会有风险。
Samesite=Strict
这种称为严格模式,代表这个 Cookie 在任何状况下都不可能做为第三方 Cookie,绝无例外
Set-Cookie: foo=1; Samesite=Strict
Set-Cookie: bar=2; Samesite=Lax
Set-Cookie: baz=3
复制代码
咱们在 a.com 下发起对 b.com 的任意请求,foo 这个 Cookie 都不会被包含在 Cookie 请求头中,但 bar 会。举个实际的例子就是,假如淘宝网站用来识别用户登陆与否的 Cookie 被设置成了 Samesite=Strict,那么用户从百度搜索页面甚至天猫页面的连接点击进入淘宝后,淘宝都不会是登陆状态,由于淘宝的服务器不会接受到那个 Cookie,其它网站发起的对淘宝的任意请求都不会带上那个 Cookie。
Samesite=Lax
这种称为宽松模式,比 Strict 放宽了点限制:假如这个请求是这种请求(改变了当前页面或者打开了新页面)且同时是个GET请求,则这个Cookie能够做为第三方Cookie。
注意
另一个问题是Samesite的兼容性不是很好,现阶段除了重新版Chrome和Firefox支持之外,Safari以及iOS Safari都还不支持,现阶段看来暂时还不能普及。
并且,SamesiteCookie目前有一个致命的缺陷:不支持子域。例如,种在topic.a.com下的Cookie,并不能使用a.com下种植的SamesiteCookie。这就致使了当咱们网站有多个子域名时,不能使用SamesiteCookie在主域名存储用户登陆信息。每一个子域名都须要用户从新登陆一次。
仅用于我的整理,参考: