Web开发的安全之旅 | 青训营笔记

92 阅读2分钟

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

一、知己知彼

跨站脚本攻击(Cross-Site Scripting)

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

image.png

XSS主要利用的是开发者盲目提交的内容和我们直接把字符串读出来生成dom结构

image.png

XSS的一些特点

  • 1、通常难以从UI上感知(暗地执行脚本)
  • 2、窃取用户信息(cookie/token)
  • 3、绘制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>`
}

如果我是攻击者,就可以在我提交的内容content中做手脚

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

那么数据把我的content内容返给HTML的时候,页面就会出现“XSS”的弹窗

这就是最简单的XSS的攻击方式

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

存储型XSS攻击(Stored XSS)

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

Stored XSS

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

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

反射形态 XSS 攻击(Reflected XSS)

Reflected XSS

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

基于DOM的XSS攻击

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

url不变 image.png

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

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

image.png

CSRF demo

image.png 用户收到了一个来自攻击者发送的伪银行链接,接到请求银行的接口,最后请求成功,用户的钱就白给了。

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"/>

注入攻击(Injection)

一般是sql注入(SQL Injection),在请求上会有sql的参数,这个参数就会被攻击者利用

image.png

Injection demo

public async renderForm(ctx) {
    const { username,form_id } = ctx.query
    const result = await sql.query(`
        SELECT a, b c FROM table
        WHERE username = ${username}
        AND form_id = ${form_id}
    `)
    ctx.body = rederForm(result)
}

攻击者可以构造一个请求,传递一个username,username的内容可以是任意字符串,比如下面的案例就成功达成被动删库跑路成就 image.png

注入攻击(Injection)不止于SQL

image.png

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——读取+修改

image.png

服务拒绝(Denial of Service DoS)

攻击者会通过某种方式(构造特定请求),导致服务器资源被显著消耗,来不及响应更多请求,导致请求挤压进而服务器崩溃;
就是短时间内,来自大量僵尸设备的请求流量,服务器不能及时完成全部请求,导致请求堆积,进而雪崩效应,无法响应新请求;简单粗暴!

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

image.png

二、百战百胜

XSS防御

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

image.png

XSS——现成工具

前端

image.png

XSS——耗子尾汁

  • 【用户需求】不讲武德,必须动态生成 DOM
  • 禁止直接将string转换成DOM

image.png

  • 谨慎——上传svg

image.png

  • 谨慎Blob 动态生成script

image.png

  • 谨慎自定义跳转链接

image.png

  • 谨慎——自定义样式

image.png

Content Security Policy(CSP)

image.png

csp就是规定好一些安全的域名,然后统一排斥其他陌生域名,避免陌生链接的跳转,主流的配置就是在服务器的响应头部配置

Content-Security-Police: script-src 'seft'   同源
Content-Security-Police: script-src 'seft' http://domain.com
复制代码

上面第一个配置就是只允许同源,第二个是加了允许的域名

前端可以在HTML中写浏览器meta信息

<meta> http-equiv = "Content-Srcurity-Police" content = "script-src self"</meta>
复制代码

CSRF的防御

我们知道,csrf是通过伪造请求,那么我们可以通过限制请求来进行防御,伪造请求就判定为异常来源

image.png

CSRF--token

image.png

image.png

CSRF--iframe攻击

image.png

Injection防御

首先防御数据库被注入

image.png

image.png

DDOS的防御

这就是运维同学的工作了,开发基本不管

image.png

image.png

image.png

3.完结

感谢阅读