Web开发的安全之旅

141 阅读4分钟

这是我参与「第四届青训营 」笔记创作活动的第13天

一、Web 安全一窥

安全问题“很常见”,会危害

  • 用户
  • 公司
  • 程序员(祭天)

二、两个角度看web安全

  • 假如你是一个 hacker ——攻击
  • 假如你是一个开发者 ——防御

攻击篇

1、Cross-Site Scripting(XSS)

1、什么是XSS?

XSS就是在我们的开发维护的页面中,攻击者将他的恶意代码注入进来了

可能导致用户的隐私泄露,或者成为攻击者挖矿的机器

2、XSS主要利用了

  • 作为开发者的我们【盲目信任用户的提交内容】
  • 作为前端工程师我们直接将用户的字符串转换成DOM

这些都可能导致XSS攻击

3、XSS的一些特点

  • 1、通常难以从UI上感知(暗地执行脚本)
  • 2、窃取用户信息(cookie/token)
  • 3、绘制UI(例如弹窗),诱骗用具点击/填写表单

4、XSS demo

系统代码:

没有对用户提交的数据进行过滤,在使用的时候也没有过滤

public async submit(ctx) {
    const { content, id } = ctx.requst.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.stringify({
    id: "1",
    content: '<script>alert("xss");</script>'
  });
});

结果如下:

ctx.body = '
  <div>
    <script>alert("xss");</script>
  </div>';

存储型XSS攻击(Stored XSS)

顾名思义,这种XSS攻击会被存储到数据库之中

Stored XSS

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

例如攻击一个视频,当所有用户看到这个视频都会看到攻击者自己添加的数据

反射形态 XSS 攻击(Reflected XSS)

Reflected XSS

  • 不涉及数据库
  • 完全从 URL 上攻击
  • 在server(服务端)注入脚本
例子

系统代码

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

系统代码中通过param来获取数据

如果攻击者输入如下URL:

url = host/path/param=

将会向网页中注册一个事件

基于DOM的XSS攻击

完全不需要服务器的参与,完全在浏览器端执行

URL不变

url = host/path/param=

执行环境发生改变

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

Mutation-based XSS

  • 利用了浏览器渲染 DOM 的特性 (独特优化)
  • 不同浏览器,会有区别(按浏览器进行攻击)
<noscript><p title="</noscript><img src=x onerror=alert(1)>">
//浏览器会渲染成如下代码
<div>
  <noscript><p title="</noscript>
  <img src="x" onerror="alert(1)">
  "">"
</div>

Cross-site request forgery(CSRF)【跨站伪造请求】

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

CSRF demo

用户收到了一个来自攻击者发送的伪银行链接,接到请求银行的接口,最后请求成功,用户的钱就会被转走。

CSRF——GET

图片一加载就发送了一次请求

<a href="https://bank.com/transfer?to=hacker&amout=100">点我抽奖
<!--确实中奖了>
<img style="display:none;" src="https://bank.com/transfer?to=hancker&amout=100"/>

CSRF——beyond GET

三、Injection(注入攻击)

一、SQL Injection

Injection demo1

攻击者可以进行如下攻击(删库跑路)

Injection 不至于SQL

  • CLI
  • OS command
  • Server-Side Request Forgery(SSRF),服务端伪造请求
    • 严格而言,SSRF不是injection,但是原理类似

Injection demo2——执行

执行环境

public async convertVideo(ctx) {
  const { video, options } = ctx.request.body;
  exec('convert-cli ${video} -o ${options}');
  ctx.body = "ok";
}

攻击者提交信息

fetch("/api", {
  method: "POST"
  body: JSON str ingify({
    options:'&& rm -rf xxx'
  })
});

执行结果

const comman = 'covert-cli video - o && rm -rf xxx'

Injection demo2——读取+修改

危害

  • 1、流量转发到真是第三方
  • 2、第三方扛不住新增流量
  • 3、第三方服务挂掉
  • 4、您的竞争对手已下线

SSRF demo

Denial of Service(DoS)

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

播插:正则表达式——贪婪模式

重复匹配时 [ ? ] vs [ no ?] :满足“一个”即可 vs 尽量多

const greedyRegExp = /a+/ ;			有多少匹配多少
const nonGreedyRegExp = /a+?/;	有一个就行
const str =”aaaaaa”;
console.log(str.match(greedyRegExp)[0]); // "aaaaa
console.log(str.match(nonGreedyRegExp)[0]); // "a ”

ReCos:基于正则表达式的 DoS

贪婪:那次不行?n-1次再试试?——回溯

Distributed DoS(DDoS)

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

「不搞复杂的,量大就完事儿了」

DDoS

攻击特点

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

中间人攻击

防御篇

XSS

  • 永远不信任用户的提交内容
  • 不要将用户提交美容直接转换成DOM

XSS——现成工具

前端

  • 主流框架默认防御XSS
  • google-closure-library

服务端(Node)

  • DOMPurify

XSS——耗子尾汁

  • 【用户需求】不讲武德,必须动态生成 DOM
  • 禁止直接将string转换成DOM
  • 谨慎——上传svg
<svg>
  <script>alert("xss");</script>
</svg>
  • 谨慎自定义跳转链接

  • 谨慎——自定义样式

插播:Same-origin Policy

  • 协议
  • 域名
  • 端口

Content Security Policy(CSP)

CSP

  • 哪些源(域名)被认为时最安全的
  • 来自安全源的脚本可以执行,否则直接抛错
  • 对 eval + inline script 说no

CSP

CSRF的防御

CSRF——token

CSRF——iframe攻击

\