这是我参与「第五届青训营」伴学笔记创作活动的第 10 天。
Cross-Site Scripting(XSS)
盲目信任用户的提交内容,直接将其拼接入DOM中,从而导致恶意代码被插入。
常见的拼接方式:
document.write();element.innerHTML = anyString;SSR(user_data)
攻击特点:
- 通常难以从UI上感知(暗地执行脚本)
- 窃取用户信息(cookie/token)
- 绘制UI(例如弹窗),诱骗用户点击/填写表单
例子:
public async submit(ctx) {
const { content, id } = ctx.request.body;
await db.save({
content, // 没有对 content 过滤
id,
});
}
public async render(ctx) {
const { content } = await db.query({
id: ctx.query.id,
});
ctx.body = `<div>${content}</div>`; // 没有对 content 过滤
}
分类
-
存储型XSS(Stored XSS)
- 恶意脚本被存在数据库中
- 访问页面(读数据)= 被攻击
- 危害最大,对全部用户可见
-
反射型XSS(Reflected XSS)
- 不涉及数据库
- 从URL上攻击
- 需要服务端对请求渲染后返回浏览器执行才能完成攻击
例如,对于下述请求渲染函数
public async render(ctx) { const { param } = ctx.query; ctx.body = `<div>${param}</div>`; }构造如下请求URL:
host/path/?param=<script>alert('123')</script> -
DOM-based XSS
- 不需要服务器的参与
- 恶意攻击的发起&执行全在浏览器完成
例如:(浏览器脚本中存在如下代码)
const content = new URL(location.href).searchParams.get("param"); const div = document.createElement("div"); div.innerHTML = content; // 没有对 content 过滤 document.body.append(div); -
Mutation-based XSS
- 利用了浏览器渲染DOM的特性(独特优化)
- 不同浏览器,会有区别(按浏览器进行攻击)
例如:利用部分浏览器对title属性的错误处理方式
<noscript><p title="</noscript><img src=x onerror=alert(1)"></noscript>浏览器会错误渲染为:
<noscript><p title="</noscript> <img src="x" onerror="alert(1)"> "">"
Cross-Site Request Forgery(CSRF)
- 在用户不知情的前提下
- 利用用户权限(cookie)
- 构造指定HTTP请求,窃取或修改用户敏感信息
【场景示例】
- 用户没有访问银行页面
- 恶意页面请求网银转账(请求自动附带上用户机器中的Cookie)
- 网银服务器检查Cookie是合法的之后,完成请求
【具体例子】
-
GET请求
<a href="https://bank.com/transfer?to=hacker&amount=100">抽奖</a> <img style="display:none;" src="https://bank.com/transfer?to=hacker&amount=100" /> -
POST请求
<form action="https://bank/transfer_tons_of_money" method="POST"> <input name="amount" value="1000000000000" type="hidden" /> <input name="to" value="hacker"type="hidden" /> </form>
注入(Injection)
SQL 注入
类似于XSS,只是改为通过网页请求传递精心设计的查询参数,使得SQL查询执行攻击者期望的动作。
攻击的关键点:直接将HTTP请求参数拼接入SQL语句中
【例子】
public async renderForm(ctx) {
const { username, form_id } = ctx.query;
const result = await sql.query(`
SELECT a, b, c FROM table
WHERE username = ${username}
`);
ctx.body = renderForm(result);
}
如果username取值为"any; DROP TABLE table;",那么就会执行如下SQL语句:
SELECT a, b, c FROM table
WHERE username = any;
DROP TABLE table;
从而导致数据表被删除。
Injection 不止于SQL
-
CLI
【例子】
public async convertVideo(ctx) { const { video, options } = ctx.request.body; exec(`convert-cli ${video} -o ${options}`); ctx.body ="ok"; }如果
options取值为&& rm -rf xxx,那么就会执行如下CLI命令:convert-cli somevideo.mp4 -o && rm -rf xxx从而导致文件被删除。
-
服务端伪造请求(Server-Side Request Forgery,SSRF)
严格而言,SSRF不是injection,但是原理类似
借用服务端的内网访问权限来获取内网的信息
假设可以通过注入获取系统文件的读取/修改权限,特别是一些重要的配置文件:
/etc/passwd/etc/shadow~/.ssh/etc/apache2/httpd.conf/etc/nginx/nginx.conf
那么,有可能会导致服务端称为攻击者的攻击工具。例如,修改NGNIX配置使得所有访问请求都跳转到攻击者设计需要攻击的网址,那么这一网址相当于接收所有该服务器的流量,实现了DDoS攻击(见下一节)。
Denial of Service(DoS)
通过某种方式(构造特定请求),导致服务器资源被显著消耗,来不及响应更多请求,导致请求挤压,进而雪崩效应。
-
ReDoS:基于正则表达式的 DoS
-
Logical DoS:反复触发复杂的数据库请求
- 耗时的同步操作
- 数据库写入
- SQL join
- 文件备份
- 循环执行逻辑
-
Distributed DoS(DDoS):短时间内,来自大量僵尸设备的请求流量,服务器不能及时完成全部请求,导致请求堆积,进而雪崩效应,无法响应新请求。
攻击特点:
- 直接访问IP
- 任意API
- 消耗大量带宽(耗尽)