安全-常见攻击形式
XSS
跨网站指令码(Cross-site scripting, 简称XSS, 使用CSS会混淆), XSS攻击通常指的是利用网页开发留下的漏洞, 通过巧妙的注入恶意指令代码到网页, 使用户加载并执行攻击者恶意制造的网页程序. 这些恶意网页程序通常是JavaSCript, 但实际上也可以包括Java, VBScript, ActiveX, Flash或者是普通的HTML. 攻击成功后, 攻击者可能得到包括不限于更高的权限, 私密网页内容, 会话和cookie等各种内容.
XSS 分为三种: 非持久型, 持久型以及 DOM-based
- 反射型: 发射型跨站脚本漏洞, 最普遍的类型. 用户访问服务器-跨站链接-返回跨站代码
- 存储型: 跨站代码存储在服务器中(数据库)
- DOM型: 客户端脚本处理逻辑导致的安全问题
存储型XSS的攻击步骤
- 攻击者将恶意代码提交到目标网站的数据库中
- 用户打开目标网站时, 网站服务端将恶意代码从数据库中取出, 拼接在html中返回给浏览器
- 用户浏览器接收到响应后解析执行, 混在其中的恶意代码也被执行了
- 恶意代码窃取用户的数据并发送到攻击者的网站, 或者冒充用户的行为, 调用目标网站接口执行攻击者指定的操作
反射型SXX的攻击步骤
- 攻击者构造出特殊的URL, 其中包含恶意代码
- 用户打开带有恶意代码的URL时, 网站服务端将恶意代码从URL中取出, 拼接在html中返回给浏览器
- 用户浏览器接收到响应后解析执行, 混在其中的恶意代码也被执行了
- 恶意代码窃取用户的数据并发送到攻击者的网站, 或者冒充用户的行为, 调用目标网站接口执行攻击者指定的操作
DOM型XSS
- 攻击者构造出特殊的URL, 其中包含恶意代码
- 用户打开带有恶意代码的URL
- 用户浏览器接收到响应后解析执行, 前端js取出url中的恶意代码并且执行
- 恶意代码窃取用户数据并发送到攻击者的网站, 或者冒充用户的行为, 调用目标网站接收执行攻击者指定的操作
XSS的防御
XSS攻击的两个要素:
- 攻击者提交恶意代码
- 浏览器执行恶意代码
针对第一个个攻击要素, 常见的方式是进行如下的转义:
function escape(str) {
str = str.replace(/&/g, '&');
str = str.replace(/</g, '<');
str = str.replace(/>/g, '>');
str = str.replace(/"/g, '&quto;');
str = str.replace(/'/g, ''');
str = str.replace(/`/g, '`');
str = str.replace(/\//g, '/');
return str;
}
对于富文本来说,可以采用白名单过滤的方式:
var xss = require('xss');
var html = xss('<h1 id="title">XSS Demo</h1><script>alert("xss");</script>');
// -> <h1>XSS Demo</h1><script>alert("xss");</script>
console.log(html);
以上实例使用了js-xss来实现, 可以看到在输出中保留了h1标签, 过滤了script标签.
我们在用户输入的过程中, 过滤掉用户输入的恶劣代码, 然后提交给后端, 但是如果攻击者绕开前端请求, 直接构造请求就不能防御了
而如果在后端写入数据库前, 对输入进行过滤, 那这个内容可能在不同的地方有不同的显示.
比如, 正常用户输入了5 < 7字符串, 在写入前转译了, 变为5 < 7.
在客户端中, 一旦经过了escapeHTML(), 就会变成乱码.
在前端中, 不同的位置所需要的编码也不同:
- 当
5 < 7作为HTML凭借页面的是偶, 可以正常的显示 - 但是如果
5 < 7作为ajax返回的话, 就不能用于vue等模板的展示, 也不能用于内容长度的计算, 标题, alert等.
过滤不一定是可靠的.
下面就要通过防止浏览器执行恶意代码:
在使用内容输入方法的时候要特别小心: .innerHTML、.outerHTML、document.write(), 不要把不可行的数据作为html插入的页面上, 尽量使用.textContent, setAttribute等.
如果使用vue/react可以不使用v-html/dangerouslySetInnerHTML, 在前端render阶段避免innerHTML, outerHTML的XSS隐患.
DOM 中的内联事件监听器,如 location、onclick、onerror、onload、onmouseover 等,<a> 标签的 href 属性,JavaScript 的 eval()、setTimeout()、setInterval() 等,都能把字符串作为代码运行。如果不可信的数据拼接到字符串中传递给这些 API,很容易产生安全隐患,请务必避免.
<!-- 链接内包含恶意代码 -->
< a href=" ">1</ a>
<script>
// setTimeout()/setInterval() 中调用恶意代码
setTimeout("UNTRUSTED")
setInterval("UNTRUSTED")
// location 调用恶意代码
location.href = 'UNTRUSTED'
// eval() 中调用恶意代码
eval("UNTRUSTED")html
</script>
比较靠谱的策略就是CSP, 这部分可以参考[Web 安全策略]('/性能与安全/8. Web 安全策略.html')中关于CSP的相关介绍.
CSRF
跨站请求伪造(Cross-sit request forgery), 也被称为 one-click attack 或者 session riding, 通常缩写为 CSRF/XSRF, 是一种挟制用户在当前已经登录的 Web 应用程序上执行非本意的操作的攻击方式, 与 XSS 相比, XSS 利用的是用户对指定网站的信任, CSRF利用的是网站对用户网页浏览器的信任.
简单的说, CSRF 就是利用用户的登录状态发起恶意请求.
如何攻击
一个典型的CSRF攻击如下:
- 受害者登录
a.com, 并且保留了登录凭证(Cookie) - 攻击者引诱受害者访问
b.com b.com向a.com发送了一个请求:a.com/act=xx. 浏览器会默认携带a.com的cookiea.com接受到请求之后, 对请求进行验证, 并确认是受害者的凭证, 误以为是受害者自己发送的请求a.com以受害者的名义执行了act=xx- 攻击完成, 攻击者在受害者不不知情的情况下, 冒充受害者, 让
a.com执行了自己定义的操作.
假设网站中有一个通过 Get 请求提交用户评论的接口,那么攻击者就可以在钓鱼网站中加入一个图片,图片的地址就是评论接口,
<img src="http://www.domain.com/xxx?comment='attack'" />
如果是 POST 接口, 则需要表单来提交接口:
<form action="http://www.domain.com/xxx" id="CSRF" method="post">
<input name="comment" value="attack" type="hidden" />
</form>
访问这个页面中, 表单就会自动提交, 相当于模拟用户完成了一次POST操作.
如何防御
CSRF的特点在于:
- 攻击一般发起在第三方网站, 而不是被攻击的网站. 被攻击的网站无法防止攻击发火说呢过
- 攻击利用受害者在被攻击网站的登录凭证, 冒充受害者他提交操作; 而不是直接窃取数据
- 整个过程攻击者并不能获取受害者的登录凭证, 仅仅是"冒用"
- 跨站请求可以用各种方式, 包括图片的URL, 超链接, CORS, Form提交等. 部分请求方式可以直接嵌入在第三方的论坛, 文章, 难以追踪.
防范 CSRF 可以遵循以下规则:
- 阻止不明外域的访问
- 同源检测
- samesite cookie
- 提交时要求附加本域才能获取的信息
- CSRF Token
- 双重cookie验证
SameSite
可以对 Cookie 设置 SameSite 属性, 该属性设置 Cookie 不随着跨域请求发送, 该属性可以很大程度减少 CSRF 的攻击, 但是该属性目前并不是所有浏览器都兼容.
验证 Referer
对于需要防范 CSRF 的请求, 我们可以通过验证 Referer 来判断该请求是否为第三方网站发起的.
Token
服务器下发 Token, 每次请求都要携带 Token.
流程如下:
- 用户代开页面的时候, 服务器需要给这个用户生成一个token
- 对于get请求, token将附在请求地址之后. 对于POST请求来说, 可以附在form的最后
<input type=”hidden” name=”csrftoken” value=”tokenvalue”/>
- 当用户从客户端得到了Token, 再次提交给服务器的时候, 服务器需要判断token的有效性.
SQL 注入
Sql 注入攻击,是通过将恶意的 Sql 查询或添加语句插入到应用的输入参数中,再在后台 Sql 服务器上解析执行进行的攻击.
流程大致如下:
- 找出SQL漏洞的注入点
- 判断数据库的类型以及版本
- 猜解用户名和密码
- 利用工具查找web后台管理入口
- 入侵和破坏
预防的方式如下:
- 严格检查输入变量的类型和格式
- 过滤和转译特殊字符
- 对访问数据库的
web应用程序采用web应用防火墙