跳到主要内容

安全-常见攻击形式

XSS

跨网站指令码(Cross-site scripting, 简称XSS, 使用CSS会混淆), XSS攻击通常指的是利用网页开发留下的漏洞, 通过巧妙的注入恶意指令代码到网页, 使用户加载并执行攻击者恶意制造的网页程序. 这些恶意网页程序通常是JavaSCript, 但实际上也可以包括Java, VBScript, ActiveX, Flash或者是普通的HTML. 攻击成功后, 攻击者可能得到包括不限于更高的权限, 私密网页内容, 会话和cookie等各种内容.

XSS 分为三种: 非持久型, 持久型以及 DOM-based

  • 反射型: 发射型跨站脚本漏洞, 最普遍的类型. 用户访问服务器-跨站链接-返回跨站代码
  • 存储型: 跨站代码存储在服务器中(数据库)
  • DOM型: 客户端脚本处理逻辑导致的安全问题

存储型XSS的攻击步骤

  1. 攻击者将恶意代码提交到目标网站的数据库中
  2. 用户打开目标网站时, 网站服务端将恶意代码从数据库中取出, 拼接在html中返回给浏览器
  3. 用户浏览器接收到响应后解析执行, 混在其中的恶意代码也被执行了
  4. 恶意代码窃取用户的数据并发送到攻击者的网站, 或者冒充用户的行为, 调用目标网站接口执行攻击者指定的操作

反射型SXX的攻击步骤

  1. 攻击者构造出特殊的URL, 其中包含恶意代码
  2. 用户打开带有恶意代码的URL时, 网站服务端将恶意代码从URL中取出, 拼接在html中返回给浏览器
  3. 用户浏览器接收到响应后解析执行, 混在其中的恶意代码也被执行了
  4. 恶意代码窃取用户的数据并发送到攻击者的网站, 或者冒充用户的行为, 调用目标网站接口执行攻击者指定的操作

DOM型XSS

  1. 攻击者构造出特殊的URL, 其中包含恶意代码
  2. 用户打开带有恶意代码的URL
  3. 用户浏览器接收到响应后解析执行, 前端js取出url中的恶意代码并且执行
  4. 恶意代码窃取用户数据并发送到攻击者的网站, 或者冒充用户的行为, 调用目标网站接收执行攻击者指定的操作

XSS的防御

XSS攻击的两个要素:

  • 攻击者提交恶意代码
  • 浏览器执行恶意代码

针对第一个个攻击要素, 常见的方式是进行如下的转义:

function escape(str) {
str = str.replace(/&/g, '&');
str = str.replace(/</g, '&lt;');
str = str.replace(/>/g, '&gt;');
str = str.replace(/"/g, '&quto;');
str = str.replace(/'/g, '&#39;');
str = str.replace(/`/g, '&#96;');
str = str.replace(/\//g, '&#x2F;');
return str;
}

对于富文本来说,可以采用白名单过滤的方式:

var xss = require('xss');
var html = xss('<h1 id="title">XSS Demo</h1><script>alert("xss");</script>');
// -> <h1>XSS Demo</h1>&lt;script&gt;alert("xss");&lt;/script&gt;
console.log(html);

以上实例使用了js-xss来实现, 可以看到在输出中保留了h1标签, 过滤了script标签.

我们在用户输入的过程中, 过滤掉用户输入的恶劣代码, 然后提交给后端, 但是如果攻击者绕开前端请求, 直接构造请求就不能防御了

而如果在后端写入数据库前, 对输入进行过滤, 那这个内容可能在不同的地方有不同的显示.

比如, 正常用户输入了5 < 7字符串, 在写入前转译了, 变为5 &lt; 7.

在客户端中, 一旦经过了escapeHTML(), 就会变成乱码.

在前端中, 不同的位置所需要的编码也不同:

  • 5 < 7作为HTML凭借页面的是偶, 可以正常的显示
  • 但是如果5 < 7作为ajax返回的话, 就不能用于vue等模板的展示, 也不能用于内容长度的计算, 标题, alert等.

过滤不一定是可靠的.

下面就要通过防止浏览器执行恶意代码:

在使用内容输入方法的时候要特别小心: .innerHTML.outerHTMLdocument.write(), 不要把不可行的数据作为html插入的页面上, 尽量使用.textContent, setAttribute等.

如果使用vue/react可以不使用v-html/dangerouslySetInnerHTML, 在前端render阶段避免innerHTML, outerHTML的XSS隐患.

DOM 中的内联事件监听器,如 location、onclick、onerror、onload、onmouseover 等,<a> 标签的 href 属性,JavaScripteval()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.coma.com发送了一个请求: a.com/act=xx. 浏览器会默认携带a.comcookie
  • a.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应用防火墙

参考链接