Web安全| 青训营笔记

286 阅读7分钟

从两个角度来学习web安全

攻击篇

Cross-Site Scripting(XSS)

跨站脚本攻击,在页面中注入恶意脚本(如script标签),当用户访问页面时,恶意脚本会被执行,完成攻击。

XSS攻击的原理:

  • 开发者盲目信任用户的提交内容
  • 开发者直接将用户提交的string转换为DOM

XSS的特点:

  • 难以从UI上感知
  • 会窃取用户信息(cookie/token)
  • 绘制UI,诱导用户点击/填写表单

XSS攻击示例

服务端接口:

// 从用户提交的内容中提取字段存储到数据库中
public async submit(ctx) {
    const { content, id } = ctx.request.body;
    // 未对content进行过滤
    await db.save({
        content,
        id
    });
}

// 从数据库中读取字段并渲染页面
public async render(ctx) {
    const { content } = await db.query({
        id: ctx.query.id
    });
    // 未对content进行过滤
    ctx.body = '<div>${content}</div>'
}

攻击者可以直接提交恶意脚本:

// 提交
fetch("/submit", {
    body: JSON.stringfy({
        id: "1",
        content: `<script>alert("xss")</script>`
    });
});

// 渲染
ctx.body = `
    <div>
        <script>alert("xss")</script>
    </div>`;

XSS的分类

Stored XSS

存储型XSS攻击:

  • 恶意脚本被存储在数据库中
  • 访问页面时读数据导致被攻击
  • 危害最大,对全部用户可见

Reflected XSS

反射型XSS攻击:

  • 不涉及数据库
  • 从URL上进行攻击

反射型XSS攻击示例: URL中包含query参数,服务端从URL中读取字段并生成HTML片段。 攻击者可以通过修改query参数,生成恶意的HTML标签,从而在用户访问页面时命中XSS攻击

URL:

host/path/?param=<script>alert("xss")</script>

服务端代码:

public async render(ctx) {
    const { param } = ctx.query;
    ctx.status = 200;
    ctx.body = `<div>${param}</div>`;
}

DOM-based XSS

基于DOM的XSS攻击:

  • 不需要服务器的参与
  • 恶意攻击的发起及执行,均在浏览器完成

URL:

host/path/?param=<script>alert("xss")</script>

浏览器中代码:

// 获取param参数
const content = new URL(location.href).searchParams.get("param");
const div = document.creatElement("div");
// 注入恶意脚本
div.innerHTML = content;
document.body.append(div);

基于DOM的XSS攻击与反射型XSS攻击的区别在于完成注入脚本的地方: image.png image.png

Mutation-based XSS

基于区别的XSS攻击:

  • 利用了浏览器渲染DOM的特性(独特优化)
  • 不同的浏览器存在区别(按浏览器进行攻击)

基于区别的XSS攻击示例:

noscript标签:

<noscript><p title="</noscript><img src=x onerror=alert(1)>">

Chrome浏览器渲染HTML片段:

<div>
    <noscript><p title="</noscript>    // </noscript>会关闭noscript标签
    <img src="x" onerror="alert(1)">   // img被视为标签,其src属性不合法,进而触发onerror事件回调,完成XSS攻击
    "">"
</div>

Cross-Site request forgery(CSRF)

跨站伪造请求:

  • 在用户不知情的前提下
  • 利用用户权限(cookie)
  • 构造指定HTTP请求,窃取或修改用户敏感信息

CSRF攻击示例: image.png 过程中:

  • 用户没有访问银行页面
  • 银行页面中的特定接口被请求
  • 利用用户cookie,请求执行成功

CSRF的分类

GET请求

示例:

<!-- 点击链接时触发 -->
<a href="http://bank.com/transfer?to=hacker&amount=100">您中奖了</a>
<!-- 加载img时触发 -->
<img style="display:none;" src="http://bank.com/transfer?to=hacker&amount=100"/>

beyond GET请求

示例:

<!-- 为表单设置POST方法 -->
<form action="https://bank/transfer_tons_of_money" method="POST">
    <!-- 为input标签设置hidden属性 -->
    <input name="amount" value="1000000" type="hidden"/>
    <input name="to" value="hacker" type="hidden"/>
</form>

Injection

注入攻击,最常见的注入攻击:SQL Injection

SQL注入攻击流程:

  1. 在HTTP请求上恶意注入SQL参数
  2. 请求到达服务器端,服务器端从请求上读取参数得到SQL语句并运行
  3. SQL运行结果可能是攻击者获取其他数据、修改数据、删除数据等

SQL注入示例:

服务器代码:

public async renderForm(ctx) {
    // 1. 读取请求字段
    const { username, form_id } = ctx.query;
    // 2. 直接以字符串的形式拼接SQL语句
    const result = await sql.query(`
        SELECT a, b, c FROM table
        WHERE username = ${username}
        AND form_id = ${form_id}
    `);
    ctx.body = renderForm(result);
}

攻击者代码:

fetch("/api", {
    method: "POST",
    headers: {
        "Content-Type": "application/json"
    },
    body: JSON.stringfy({
        username: "any; DROP TABLE table",
        // SQL语句会变为 SELECT XXX FROM XXX; DROP TABLE table
    })
})

其他类型的Injection

  • CLI,命令行
  • OS Command,系统命令
  • Server-Side Request Forgery(SSRF),服务端伪造请求
    • 严格而言,SSRF不是注入攻击,但原理类似

系统命令Injection示例:

Injection执行删除

服务端代码:

// 用于转换视频,接受options参数
public asnc converVideo(ctx) {
    const { video, options } = ctx.request.body;
    exec(`convert-cil ${video} -o ${options}`);
    ctx.body = "ok";
}

攻击者代码:

fetch("/api", {
    method: "POST",
    body: JSON.stringfy({
        options: `' && rm -rf xxx`    // 传入rm系统命令
    })
});

const command = `convert-cil video -o && rm -rf xxx`

Injection读取+修改

当可以为攻击者执行任何语句时,攻击者就可以读或修改服务器上的任何文件,这是十分危险的。 常见的重要文件有:

  • /etc/passwd
  • /etc/shadow
  • ~/.ssh
  • /etc/apache2/httpd.conf
  • etc/nginx/nginx.conf
    • 通过修改Nginx配置可以将流量转发到真实第三方
    • 第三方可能会承受不了新流量而服务挂掉

SSRF示例

服务端伪造请求:

  1. 请求用户自定义的callback URL
  2. web server通常有内网访问权限
public async webhook(ctx) {
    // callback可能是内网url,访问callback会暴露内网信息
    ctx.body = await fetch(ctx.query.callback);
}

Denial of Service(DoS)

攻击者通过某种方式(构造特定请求),导致服务器资源被显著消耗,来不及响应更多请求,导致请求挤压,进而雪崩效应。

ReDoS:基于正则表达式的DoS

image.png

Distributed DoS(DDoS)

短时间内,来自大量僵尸设备的请求流量,服务器不能及时完成全部请求,导致请求堆积,进而雪崩效应,无法响应新请求。

DDoS攻击特点:

  • 直接访问IP
  • 任意API
  • 消耗大量带宽(耗尽)

DDoS攻击示例:洪水攻击 攻击者发送大量TCP请求,而不返回ACK,导致三次握手无法完成,连接无法释放,从而达到最大连接数 image.png

基于传输层的攻击方式:中间人攻击

中间人攻击的原理:

  • 明文传输
  • 信息篡改不可知
  • 对方身份未验证

image.png

防御篇

XSS的防御

针对XSS攻击的防御策略:

  • 不要相信用户提交的内容
  • 不要将用户提交的内容转换为DOM

对于必须要动态生成DOM的需求:

  • string生成DOM时要对string进行转译
  • 对SVG文件要进行扫描,SVG中可以包含<script></script>标签
  • 对于用户自定义跳转行为要做好过滤,自定义跳转可以传递JS代码
  • 对于自定义样式的地方,要注意可以设置URL的位置

Content Security Policy(CSP)

同源策略(Same-origin Policy, SoP):同源是指协议域名端口都相同。HTTP通常对于同源的请求可行,对跨域的请求要看服务器的配置。

内容安全策略:

  • 定义一些认为是安全的源
  • 来自安全源的脚本可以执行,否则直接抛出错误
  • 对于eval和内联的script标签直接报错

CSP示例: 服务器的响应头部

Content-Security-Policy: script-src 'self'
Content-Security-Policy: script-src 'self' https://domain.com

设置浏览器meta

<meta http-equiv="Content-Security-Policy" content="script-src self">

CSRF的防御

跨站伪造请求,可以针对异常来源来防御,限制请求来源,从而限制伪造请求。

请求头部校验

可以对请求头部进行校验:

  • Origin
    • 同源请求中,GET和HEAD不发送Origin字段
  • Referer(常用)

其他判断请求来源于合法来源的方式:

token防御机制:

image.png 其中:

  • token要进行用户绑定,因为攻击者也可以使注册用户,拥有自己的token
  • token要有过期时间(前向保密),防止用户token泄露带来危害

CSRF的iframe攻击

攻击者构建页面,在其中使用iframe指向合法页面,并在iframe上覆盖button并设置穿透属性,从而通过iframe实现同源请求: image.png

防御方式:为页面设置X-Frame-Options: DENY/SAMEORIGIN响应头部,拒绝或只允许同源页面通过iframe访问页面。

SameSite Cookie:避免用户信息被携带

只对自己的cookie有响应 image.png

CSRF防御中间件

CSRF的攻击方式及防御方式过多,不能case by case的进行防御,应该使用中间件,生成各种CSRF的防御策略。

Injection的防御

针对Injection的防御思路:

  • 找到代码中查询SQL的位置
  • 使用prepared statement,将SQL语句进行提前编译

其他非SQL注入攻击的防御措施:

  • 最小权限原则,所有的命令不要通过sudo来执行,不给予root权限
  • 建立允许名单 + 过滤,只允许执行指定命令,拒绝rm等高危操作
  • 对URL类型参数进行协议、域名、IP等限制,避免访问内网

DOS的防御

Regex Dos防御:

  • 避免使用贪婪匹配
  • 使用代码扫描工具,查找存在的正则表达式,并进行性能基础测试
  • 拒绝使用用户提供的正则表达式

DDoS的防御:

  • 流量治理
    • 负载均衡,过滤策略
    • API网关,过滤策略
    • 前置CDN,抗量策略
  • 快速自动扩容,抗量策略
  • 非核心服务降级,抗量策略

传输层的防御

防御中间人:使用HTTPS。 HTTPS的特点:

  • 可靠性:加密,禁止明文传输
  • 完整性:MAC验证,确保信息未被篡改
  • 不可抵赖性:数字签名,验证双方身份