# 了解一下前端经典安全问题

# XSS

# XSS 是什么?

Cross-Site Scripting(跨站脚本攻击)简称 XSS,是一种代码注入攻击。攻击者通过在目标网站上注入恶意脚本,使之在用户的浏览器上运行。利用这些恶意脚本,攻击者可获取用户的敏感信息如 Cookie、SessionID 等,进而危害数据安全。

为了和 CSS 区分,这里把攻击的第一个字母改成了 X,于是叫做 XSS。

XSS 的本质是:恶意代码未经过滤,与网站正常的代码混在一起;浏览器无法分辨哪些脚本是可信的,导致恶意脚本被执行。

而由于直接在用户的终端执行,恶意代码能够直接获取用户的信息,或者利用这些信息冒充用户向网站发起攻击者定义的请求。

在部分情况下,由于输入的限制,注入的恶意脚本比较短。但可以通过引入外部的脚本,并由浏览器执行,来完成比较复杂的攻击策略。

这里有一个问题:用户是通过哪种方法“注入”恶意脚本的呢?

不仅仅是业务上的“用户的 UGC 内容”可以进行注入,包括 URL 上的参数等都可以是攻击的来源。在处理输入时,以下内容都不可信:

  • 来自用户的 UGC(User Generated Content) 信息,也就是用户生成内容,即用户原创内容
  • 来自第三方的链接
  • URL 参数
  • POST 参数
  • Referer (可能来自不可信的来源)
  • Cookie (可能来自其他子域注入)

# XSS 分类

# 存储型 XSS

攻击步骤:

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

这种攻击常见于带有用户保存数据的网站功能,如论坛发帖,商品评论,用户私信等

# 反射型 XSS

攻击步骤:

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

反射型 XSS 跟存储型 XSS 的区别是:存储型 XSS 的恶意代码存在数据库里,反射型 XSS 的恶意代码存在 URL 里

反射型 XSS 漏洞常见于通过 URL 传递参数的功能,如网站搜索,跳转等

由于需要用户主动打开恶意的 URL 才能生效,攻击者往往会结合多种手段诱导用户点击

POST 的内容也可以触发反射型 XSS,只不过其触发条件比较苛刻(需要构造表单提交页面,并引导用户点击),所以非常少见

# DOM 型 XSS

攻击步骤:

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

DOM 型 XSS 跟前两种 XSS 的区别:DOM 型 XSS 攻击中,取出和执行恶意代码由浏览器端完成,属于前端 JavaScript 自身的安全漏洞,而其他两种 XSS 都属于服务端的漏洞

# 预防

# 预防存储型 XSS 和反射型 XSS

存储型 XSS 和反射型 XSS 都是从服务端取出恶意代码,插入到响应 HTML 里的,攻击者刻意编写的“数据”被内嵌到代码中,被浏览器所执行

预防这两种漏洞,有两种常见的方法:

  1. 改成纯前端渲染,把代码和数据分隔开
  2. 对 HTML 做充分转义

# 预防 DOM 型 XSS

DOM 型 XSS 攻击,实际上就是网站前端 JavaScript 代码本身不够严谨,把不可信的数据当作代码执行了

在使用 .innerHTML.outerHTMLdocument.write() 时要特别小心,不要把不可信的数据作为 HTML 插到页面上,而应尽量使用 .textContent.setAttribute() 等。

如果用 Vue/React 技术栈,并且不使用 v-html/dangerouslySetInnerHTML 功能,就在前端 render 阶段避免 innerHTMLouterHTML 的 XSS 隐患。

DOM 中的内联事件监听器,如 locationonclickonerroronloadonmouseover 等,<a> 标签的 href 属性,JavaScript 的 eval()setTimeout()setInterval() 等,都能把字符串作为代码运行。如果不可信的数据拼接到字符串中传递给这些 API,很容易产生安全隐患,请务必避免。

<!-- 内联事件监听器中包含恶意代码 -->
<img onclick="UNTRUSTED" onerror="UNTRUSTED" src="data:image/png,">

<!-- 链接内包含恶意代码 -->
<a href="UNTRUSTED">1</a>

<script>
// setTimeout()/setInterval() 中调用恶意代码
setTimeout("UNTRUSTED")
setInterval("UNTRUSTED")

// location 调用恶意代码
location.href = 'UNTRUSTED'

// eval() 中调用恶意代码
eval("UNTRUSTED")
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 其他预防

# Content Security Policy

严格的 CSP 在 XSS 的防范中可以起到以下的作用:

  • 禁止加载外域代码,防止复杂的攻击逻辑。
  • 禁止外域提交,网站被攻击后,用户的数据不会泄露到外域。
  • 禁止内联脚本执行(规则较严格,目前发现 GitHub 使用)。
  • 禁止未授权的脚本执行(新特性,Google Map 移动版在使用)。
  • 合理使用上报可以及时发现 XSS,利于尽快修复问题。

关于 CSP 的详情,请关注前端安全系列后续的文章。

# 输入内容长度控制

对于不受信任的输入,都应该限定一个合理的长度。虽然无法完全防止 XSS 发生,但可以增加 XSS 攻击的难度。

# 其他安全措施
  • HTTP-only Cookie: 禁止 JavaScript 读取某些敏感 Cookie,攻击者完成 XSS 注入后也无法窃取此 Cookie。
  • 验证码:防止脚本冒充用户提交危险操作。

# CSRF

# CSRF 是什么?

CSRF(Cross-site request forgery)跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。

一个典型的 CSRF 攻击有着如下的流程:

# CSRF 分类

# GET 类型的 CSRF

GET 类型的 CSRF 的利用非常简单,只需要一个 HTTP 请求,一般会这样用

 <img src="http://bank.example/withdraw?amount=10000&for=hacker" >
1

在用户访问含有这个 img 的页面后,浏览器会自动向http://bank.example/withdraw?amount=10000&for=hacker发出一次 HTTP 请求,back.example就会收到包含用户登录信息的一次跨域请求

# POST 类型的 CSRF

这种类型的 CSRF 利用起来通常使用的是一个自动提交的表单,如:

 <form action="http://bank.example/withdraw" method=POST>
    <input type="hidden" name="account" value="xiaoming" />
    <input type="hidden" name="amount" value="10000" />
    <input type="hidden" name="for" value="hacker" />
</form>
<script> document.forms[0].submit(); </script>
1
2
3
4
5
6

访问该页面后,表单会自动提交,相当于模拟用户完成了一次 POST 操作。

POST 类型的攻击通常比 GET 要求更加严格一点,但仍并不复杂。任何个人网站、博客,被黑客上传页面的网站都有可能是发起攻击的来源,后端接口不能将安全寄托在仅允许 POST 上面。

# 链接类型的 CSRF

链接类型的 CSRF 并不常见,比起其他两种用户打开页面就中招的情况,这种需要用户点击链接才会触发。这种类型通常是在论坛中发布的图片中嵌入恶意链接,或者以广告的形式诱导用户中招,攻击者通常会以比较夸张的词语诱骗用户点击,例如:

  <a href="http://test.com/csrf/withdraw.php?amount=1000&for=hacker" taget="_blank">
  重磅消息!!
  <a/>
1
2
3

由于之前用户登录了信任的网站 A,并且保存登录状态,只要用户主动访问上面的这个 PHP 页面,则表示攻击成功。

# CSRF 特点

  • 攻击一般发起在第三方网站,而不是被攻击的网站,被攻击的网站无法防止攻击发生
  • 攻击利用用户在被攻击网站的登录凭证,冒充受害者提交操作,而不是直接窃取数据
  • 整个过程攻击者并不能获取到用户的登录凭证,仅仅是冒用
  • 跨站请求可以用各种方式:图片 URL、超链接、CORS、Form 提交等等。部分请求可以直接嵌入第三方论坛,文章中,难以进行追踪

CSRF 通常是跨域的,因为外域通常更容易被攻击者掌控。但是如果本域下有容易被利用的功能,比如可以发图和链接的论坛和评论区,攻击可以直接在本域下进行,而且这种攻击更加危险

# 防护策略

CSRF 通常从第三方网站发起,被攻击的网站无法防止攻击发生,只能通过增强自己网站针对 CSRF 的防护能力来提升安全性。

上文中讲了 CSRF 的两个特点:

  • CSRF(通常)发生在第三方域名。
  • CSRF 攻击者不能获取到 Cookie 等信息,只是使用。

针对这两点,我们可以专门制定防护策略,如下:

  • 阻止不明外域的访问
    • 同源检测
    • Samesite Cookie
  • 提交时要求附加本域才能获取的信息
    • CSRF Token
    • 双重 Cookie 验证

# 防止网站被利用

前面所说的,都是被攻击的网站如何做好防护。而非防止攻击的发生,CSRF 的攻击可以来自:

  • 攻击者自己的网站。
  • 有文件上传漏洞的网站。
  • 第三方论坛等用户内容。
  • 被攻击网站自己的评论功能等。

对于来自黑客自己的网站,我们无法防护。但对其他情况,那么如何防止自己的网站被利用成为攻击的源头呢?

  • 严格管理所有的上传接口,防止任何预期之外的上传内容(例如 HTML)。
  • 添加 Header X-Content-Type-Options: nosniff 防止黑客上传 HTML 内容的资源(例如图片)被解析为网页。
  • 对于用户上传的图片,进行转存或者校验。不要直接使用用户填写的图片链接。
  • 当前用户打开其他用户填写的链接时,需告知风险(这也是很多论坛不允许直接在内容中发布外域链接的原因之一,不仅仅是为了用户留存,也有安全考虑)。

# CSRF 其他防范措施

# CSRF 测试

CSRFTester 是一款 CSRF 漏洞的测试工具,CSRFTester 工具的测试原理大概是这样的,使用代理抓取我们在浏览器中访问过的所有的连接以及所有的表单等信息,通过在 CSRFTester 中修改相应的表单等信息,重新提交,相当于一次伪造客户端请求,如果修改后的测试请求成功被网站服务器接受,则说明存在 CSRF 漏洞,当然此款工具也可以被用来进行 CSRF 攻击

# CSRF 监控

对于一个比较复杂的网站系统,某些项目、页面、接口漏掉了 CSRF 防护措施是很可能的。

一旦发生了 CSRF 攻击,我们如何及时的发现这些攻击呢?

CSRF 攻击有着比较明显的特征:

  • 跨域请求。
  • GET 类型请求 Header 的 MIME 类型大概率为图片,而实际返回 Header 的 MIME 类型为 Text、JSON、HTML。

我们可以在网站的代理层监控所有的接口请求,如果请求符合上面的特征,就可以认为请求有 CSRF 攻击嫌疑。我们可以提醒对应的页面和项目负责人,检查或者 Review 其 CSRF 防护策略

# 点击劫持

# 点击劫持是什么?

点击劫持是指在一个 Web 页面中隐藏了一个透明的 iframe,用外层假页面诱导用户点击,实际上是在隐藏的 frame 上触发了点击事件进行一些用户不知情的操作。

典型点击劫持攻击流程:

  1. 攻击者构建了一个非常有吸引力的网页
  2. 将被攻击的页面放置在当前页面的 iframe
  3. 使用样式将 iframe 叠加到非常有吸引力内容的上方
  4. iframe设置为 100%透明
  5. 用户被诱导点击了网页内容,用户成功被攻击了

# 防御

# frame busting

Frame busting

if (top.location != window.location) {
  top.location = window.location
}
1
2
3

需要注意的是: HTML5 中 iframe 的 sandbox 属性、IE 中 iframe 的security 属性等,都可以限制 iframe 页面中的 JavaScript 脚本执行,从而可以使得 frame busting 失效。

# X-Frame-Options

X-FRAME-OPTIONS 是微软提出的一个 http 头,专门用来防御利用 iframe 嵌套的点击劫持攻击。并且在 IE8、Firefox3.6、Chrome4 以上的版本均能很好的支持。

可以设置为以下值:

  • DENY: 拒绝任何域加载
  • SAMEORIGIN: 允许同源域下加载
  • ALLOW-FROM: 可以定义允许 frame 加载的页面地址

# 中间人攻击

# 中间人攻击是什么?

中间人攻击是指,浏览器第一次请求就被攻击者拦截下来并做了修改,不给浏览器和服务器进行 HTTPS 通信的机会

攻击流程:

  1. 本地请求被劫持(如 DNS 劫持等),所有请求都发送到中间人的服务器
  2. 中间人服务器返回中间人自己的证书
  3. 客户端创建随机数,通过中间人证书的公钥对随机数加密后传送给中间人,然后凭随机数构造对称加密对传输内容进行加密传输
  4. 中间人因为有客户端的随机数,可以通过对称加密算法进行内容解密
  5. 中间人以客户端的请求内容再向正规网站发起请求
  6. 因为中间人与服务器的通信过程是合法的,正规网站通过建立的安全通道返回加密后的数据
  7. 中间人凭借与正规网站建立的对称加密算法对内容进行解密
  8. 中间人通过与服务端建立的对称加密算法对正规网站返回的数据进行加密传输
  9. 客户端通过与中间人建立的对称加密算法返回结果数据进行解密
img

由于缺少对证书的验证,所以客户端虽然发起的是 HTTPS 请求,但是客户端完全不知道自己的网络已被拦截,传输内容被中间人全部窃取

# HTTPS 为什么安全?

因为 HTTPS 保证了传输安全,防止传输过程被监听、防止数据被窃取,可以确认网站的真实性。

# HTTPS 的传输过程是怎样的?

客户端发起 HTTPS 请求,服务端返回证书,客户端对证书进行验证,验证通过后本地生成用于改造对称加密算法的随机数,通过证书中的公钥对随机数进行加密传输到服务端,服务端接收后通过私钥解密得到随机数,之后的数据交互通过对称加密算法进行加解密。

# 为什么需要证书?

防止中间人攻击,同时可以为网站提供身份证明。

# 浏览器如何验证证书的合法性?

浏览器发起 HTTPS 请求时,服务器会返回网站的 SSL 证书,浏览器需要对证书做以下验证:

  1. 验证域名、有效期等信息是否正确。证书上都有包含这些信息,比较容易完成验证;
  2. 判断证书来源是否合法。每份签发证书都可以根据验证链查找到对应的根证书,操作系统、浏览器会在本地存储权威机构的根证书,利用本地根证书可以对对应机构签发证书完成来源验证; image-20211106152911067
  3. 判断证书是否被篡改。需要与 CA 服务器进行校验;
  4. 判断证书是否已吊销。通过 CRL(Certificate Revocation List 证书注销列表)和 OCSP(Online Certificate Status Protocol 在线证书状态协议)实现,其中 OCSP 可用于第 3 步中以减少与 CA 服务器的交互,提高验证效率

以上任意一步都满足的情况下浏览器才认为证书是合法的。

# 既然证书是公开的,如果要发起中间人攻击,我在官网上下载一份证书作为我的服务器证书,那客户端肯定会认同这个证书是合法的,如何避免这种证书冒用的情况?

其实这就是非加密对称中公私钥的用处,虽然中间人可以得到证书(包含服务端的公钥、身份信息及其它相关信息),但**(服务端)**私钥是无法获取的,一份公钥是不可能推算出其对应的私钥,所以中间人拿到证书,即便能拿到客户端传过来的数据(使用服务端公钥加密过的数据),也无法伪装成合法服务端,因为无法对客户端传入的加密数据进行解密。

# 使用 HTTPS 会被抓包吗?

会被抓包,HTTPS 只防止用户在不知情的情况下通信被监听,如果用户主动授信,是可以构建中间人网络,代理软件可以对传输内容进行解密。

# SQL 注入

# 什么是 SQL 注入

SQL(Structured Query Language) 注入是一种极具破坏力的漏洞, 自从 SQL 数据库开始连接 WEB 应用的时候, SQL 注入就开始存在了, 首次发现 SQL 注入的是 Rain Forest Puppy 并引入了公众视野。

# 原理

在应用程序向后端传递 SQL 数据查询时, 如果为攻击者提供了影响该查询的能力, 就会引发 SQL 注入, 此时攻击者通过影响传递给数据库的内容来修改 SQL 自身的语法和功能, 并且影响 SQL 所支持数据库和操作系统的功能和灵活性, 对于任何不可信源获取输入代码的方式来构造动态 SQL 语句, 都很有可能收到 SQL 的注入攻击。 注入可纳取的方式:

  • 动态构建查询 SQL 语句
    • 转义字符处理不恰当:如 Oracle 中空格/双竖线/逗号等
    • 类型处理不恰当:传递注入文件路径或者写入 Webshell
    • 查询语句组装不恰当:多次组装查询语句已失去原有查询数据库的功能
    • 错误处理不恰当:详细的错误信息传递给请求客户端
    • 多个提交处理不恰当
  • 不恰当的数据配置

在预防你的数据免受注入的威胁的时候, 对输入数据进行预判和过滤将很有用, 将数据配置中权限分离, 并且将原有配置的用户进行相关配置或者密码重设, 会得到更好的预防, 在用户配置中, 很多应用系统采用的是一个用户就已经拥有 SELECT | UPDATE | INSERT | DELETE | EXECUTE 的权限, 这将很危险。

# 注入方式盘点

# 字符串内联注入

在我们对一个 SQL 的 API 进行注入'的时候如果返回的信息状态是错误信息, 那么这个 API 极度容易遭受注入的风险,如用户登陆的界面若是以下 SQL 检索语句:

SELECT * FROM TableName WHERE username = '{UserName}' AND password = '{PassWord}' ;
1

此时注入'的时候查询语句将会是错误语法, 并不能给服务器识别

SELECT * FROM TableName WHERE username = ''' AND password = '' ;
1

既然'没有被转义, 那么可以将这样的语句进行注入到上面的 SQL 查询中:

SELECT * FROM TableName WHERE username = '' OR '1' = '1'  AND password = '' OR '1' = '1';
1

而对你来说你的输入仅仅是对 Username 输入了' OR '1' = '1, 相同的 Password 输入了' OR '1' = '1来满足这条查询语句, 在很多的查询语句中可以用这个方式进行注入, 而达到获取全部数据的目的。

测试字符串 变种 SQL 语句 预期结果
' 错误语法, 返回错误信息
1' or '1' = '1 1') or ('1' = '1 恒等于真, 返回所有数据
value' or '1' = '2 value') or ('1' = ' 空条件, 返回原值相同的数据
1' or 'ab' = 'a' + 'b 1') or ('ab' = 'a' + 'b SQL Server 字符拼接, 返回所有数据
1' or 'ab' = 'a' 'b 1') or ('ab' = 'a' 'b MySQL 字符拼接, 返回所有数据
1' or 'ab' = 'a' || 'b 1') or ('ab' = 'a' || 'b Oracle 字符拼接, 返回所有数据

很多时候我们检索一条数据的详情的时候会用到唯一标识 ID, 当然有的可能用的是 UUID, 这种 UUID 可以忽略这种方式的注入, UUID 在数据库是以字符串的形式存储着, 在对于数字 ID 的类型检索内容详情的时候用到的 SQL 查询例如以下:

SELECT * FROM TableName WHERE id = {ID} ;
复制代码
1
2

在你输入已有 ID 的时候将会返回已有 ID 下的数据详情, 对于很多详情数据将会很有用, 那根据我们已有的 字符串内联注入 的方式, 我们将采取以下的方式进行注入测试:

SELECT * FROM TableName WHERE id = 1 or 1 = 1 ;
复制代码
1
2

在你对 SQL 的 API 输入1 or 1 = 1就可以达到获取所有数据详情的目的, 在注入中, 我们最简单的注入方式都是以恒等于真的条件进行注入的方式最为常见和切最为简单。

测试字符串 变种 SQL 语句 预期结果
' 错误语法, 返回错误信息
1 + 1 3 - 1 返回操作结果相同的数据
value + 0 返回与原先结果相同的数据
1 or 1 = 1 1) or (1 = 1 恒等于真, 返回所有数据
value or 1 = 2 value) or (1 = 2 空条件, 返回原值相同的数据
1 and 1 = 2 1) and (1 = 2 恒等于假, 返回空数据
1 or 'ab' = 'a' + 'b' 1) or ('ab' = 'a' + 'b' SQL Server 字符拼接, 返回所有数据
1 or 'ab' = 'a' 'b' 1) or ('ab' = 'a' 'b' MySQL 字符拼接, 返回所有数据
1 or 'ab' = 'a' || 'b' 1) or ('ab' = 'a' || 'b' Oracle 字符拼接, 返回所有数据

# 终止式 SQL 注入

在对 SQL 注入的时候, 我们可以尝试通过注释语法进行 SQL 注入:

数据库类型 注释语法 描述
SQL Server Oracle PostgreSQL -- (双连字符) 用于单行注释
/* */ 用于多行注释
MySQL -- (双连字符) 用于单行注释 要求第二个字符跟一个空格或控制字符
# 用于单行注释
/* */ 用于多行注释

如一个验证表单, 正常情况下键入一个合法的 UsernamePassword 对所登陆的用户进行验证, 若是我们采用注入代码并终止该查询语句, 就可以达到注入的目的:

SELECT * FROM TableName WHERE username='admin'/*' AND password='*/'';
1

我们注入的时候仅仅是对 Username 字段提交了 admin'/*Password 字段提交了 */' 就达到了注入的目的, 最后实际查询的 SQL 仅仅是:

SELECT * FROM TableName WHERE username='admin' '';
1

当然, 你不必仅仅是局限于查询的 SQL 语句, 我们也可以自己在更新/新增/删除的操作中插入想要的注入语句, 最后达到我们想要的目的, 这总执行多个 SQL 语句的方式, 也是利用注释的语法实现的。

# 时间延时注入

在大多数的网站上并没有 SQL 执行的报错信息返回, 所以我们难以确认是否存在漏洞, 对于这种情况, 我们可以向数据库注入时间延迟, 并查看服务器的相应是否也是延时的状态, 在执行 SQL Server 的时候仅仅需要增加:

WAITFOR DELAY 'hours:minutes:seconds'
1

如:

SELECT * FROM TableName WHERE id=1314; WAITFOR LEDAY '0:0:5'; --
1

相同的, 你在 Oracle PL/SQL 里面使用下面的语句, 也可以达到延时注入的方式:

BEGIN DBMS_LOCK.SLEEP(5); END;
1

虽然 DBMS_LOCK.SLEEP() 可以让过程休眠指定秒数, 但是这个函数不能直接注入子查询中, 并且需要数据库管理员才可以使用 DBSM_LOCK 包, 所以我们还有更好的办法, 如:

SELECT * FROM TableName WHERE id=1314 or 1=DBSM_PIPE.RECEIVE_MESSAGE('RDS', 5)
1

DBSM_PIPE.RECEIVE_MESSAGE() 函数将会为从 RDS 管道返回的数据等待 5 秒, 默认情况下, 也允许 public 权限下执行这个包的函数。 在 PostgreSQL 8.2 版本或 8.2 版本以上的版本, 可以用 PG_SLEEP() 来执行你的注入:

SELECT * FROM TableName WHERE id=1314; SELECT pg_sleep(10); --

1
2

# OS 注入

# 什么是 OS 注入

OS 命令注入和 SQL 注入差不多,只不过 SQL 注入是针对数据库的,而 OS 命令注入是针对操作系统的。OS 命令注入攻击指通过 Web 应用,执行非法的操作系统命令达到攻击的目的。只要在能调用 Shell 函数的地方就有存在被攻击的风险。倘若调用 Shell 时存在疏漏,就可以执行插入的非法命令。

命令注入攻击可以向 Shell 发送命令,让 Windows 或 Linux 操作系统的命令行启动程序。也就是说,通过命令注入攻击可执行操作系统上安装着的各种程序

# 原理

image-20211106153041076黑客构造命令提交给 web 应用程序,web 应用程序提取黑客构造的命令,拼接到被执行的命令中,因黑客注入的命令打破了原有命令结构,导致 web 应用执行了额外的命令,最后 web 应用程序将执行的结果输出到响应页面中。

我们通过一个例子来说明其原理,假如需要实现一个需求:用户提交一些内容到服务器,然后在服务器执行一些系统命令去返回一个结果给用户

// 以 Node.js 为例,假如在接口中需要从 github 下载用户指定的 repo
const exec = require('mz/child_process').exec
let params = {
  /* 用户输入的参数 */
}
exec(`git clone ${params.repo} /some/path`)
1
2
3
4
5
6

如果 params.repo 传入的是 https://github.com/admin/admin.github.io.git 确实能从指定的 git repo 上下载到想要的代码。 但是如果 params.repo 传入的是 https://github.com/xx/xx.git && rm -rf /* && 恰好你的服务是用 root 权限起的就糟糕了。

# 防御

  • 后端对前端提交内容进行规则限制(比如正则表达式)。
  • 在调用系统命令前对所有传入参数进行命令行参数转义过滤。
  • 不要直接拼接命令语句,借助一些工具做拼接、转义预处理,例如 Node.js 的 shell-escape npm

# DDOS

# DDOS 是什么?

分布式拒绝服务(DDoS:Distributed Denial of Service)攻击,是指攻击者利用大量"肉鸡"对攻击目标发动大量的正常或非正常请求、耗尽目标主机资源或网络资源,从而使被攻击的主机不能为正常用户提供服务。

# DOS 是什么?

DoS(拒绝服务,Denial of Service)就是利用合理的服务请求来占用过多的服务资源,从而使合法用户无法得到服务的响应。这是早期非常基本的网络攻击方式。在信息安全的三要素——保密性、完整性和可用性中,DoS(Denial of Service)针对的目标正是可用性。该攻击方式利用目标系统网络服务功能缺陷或者直接消耗其系统资源,使得该目标系统无法提供正常的服务。

# DDOS 攻击形式

一般来说,DDoS 攻击可以具体分成两种形式:带宽消耗型以及资源消耗型。它们都是透过大量合法或伪造的请求占用大量网络以及器材资源,以达到瘫痪网络以及系统的目的。其中,DDoS 带宽消耗攻击可以分为两个不同的层次:洪泛攻击或放大攻击

当服务器被 DDos 攻击时,一般会出现以下现象:

  • 被攻击主机上有大量等待的 TCP 连接;
  • 网络中充斥着大量的无用的数据包;
  • 受害主机无法正常和外界通讯;
  • 受害主机无法处理所有正常请求;
  • 严重时会造成系统死机。

对于用户来说,在常见的现象就是网站无法访问。

image-20211106153158496

# 反射型 DDOS 攻击(GitHub 两年前遭受过该攻击)

**本次是 GitHub 遭受攻击的手段是 DDos 攻击手段中的反射型 DDoS 攻击。反射型 DDos 攻击也被称为放大攻击。**攻击者并不直接攻击目标服务 IP,而是利用互联网的某些特殊服务开放的服务器,通过伪造被攻击者的 IP 地址、向有开放服务的服务器发送构造的请求报文,该服务器会将数倍于请求报文的回复数据发送到被攻击 IP,从而对后者间接形成 DDoS 攻击。

执行反射攻击,需要具备四个因素:

  • 一个服务器:用于执行 IP 地址欺骗;
  • 一个脆弱的、易于反射/放大的协议:任何设计不完善的、基于 UDP 请求的协议都可能被利用;
  • 反射服务器列表:支持脆弱协议的服务器;
  • 一个目标 IP 地址:受害者的 IP 地址

攻击的整体思路如下:

  • 攻击者发送虚假的 UDP 请求;
  • 伪造源 IP 地址:将请求包中的源 IP 地址替换成受害者的 IP 地址,这些请求包中通常不会出现攻击者自己的 IP 地址;
  • 每个请求包都发往一个随机的反射服务器;
  • 经过伪造的数据包通过网络传输最终到达反射服务器;
  • 反射服务器接收到这些虚假的请求包,遵从约定的协议规则,发送响应;无疑,这些响应都是针对受害目标的。

image-20211106153222289 如图所示,攻击者不直接把攻击包发给受害者,而是冒充受害者给放大器发包,然后通过放大器再反射给受害者。受害目标最终会收到大量的响应包,而这些包都不是它请求的。在攻击足够大的情况下,受害目标可能会发生网络拥塞或中断风暴。

传送给受害目标的响应可能远远大于伪造的请求,这就是这类攻击被称为“放大攻击”的原因。经过精心设计,攻击者可以利用有限的资源,有效的扩大 DDOS 攻击的流量。

在反射型攻击中,攻击者利用了网络协议的缺陷或者漏洞进行 IP 欺骗,主要是因为很多协议(例如 ICMP,UDP 等)对源 IP 不进行认证。同时,要达到更好的攻击效果,黑客一般会选择具有放大效果的协议服务进行攻击。总结一下就是利用 IP 欺骗进行反射和放大,从而达到四两拨千斤的效果。

# DDOS 攻击类型

DDOS 攻击类型数不胜数,这里从层次上分网络层攻击与应用层攻击(详细看浅谈 DDOS 攻击与防御 (opens new window)10 Major Types of DDoS Attacks and Prevention (opens new window)

网络层 DDoS 攻击常见手段有:SYN Flood、ACK Flood、Connection Flood、UDP Flood、ICMP Flood、TCP Flood、Proxy Flood 等。

应用层 DDoS 攻击不是发生在网络层,是发生在 TCP 建立握手成功之后,应用程序处理请求的时候。常见的有:CC 攻击、DNS Flood、慢速连接攻击等。

# 防范措施(没法做到彻底防范)

# Direct flood attack (UDP flood and ping flood)(UDP 洪水和 ping 洪水)

为了防止 UDP 或 ICMP 泛洪攻击,可以考虑增加带宽,部署一对负载平衡器,反映攻击并使用 IP 欺骗防护机制。 或者,可以通过订阅 DDoS 保护服务提供商来将恶意流量重新路由到第三方数据中心

# Reflection attack(反射攻击)

在网络中实施反欺骗技术,以检测和丢弃欺骗源 IP 地址

# Smurf and Fraggle attack(利用路由器广播地址)

正确地配置路由器和其他网络设备,防止有人利用你路由器的 IP 广播设施

# (TCP) SYN Flood Attack

过滤、增加积压、减少 SYN 接收定时器、回收半开的 TCP 连接、SYN 缓存、SYN cookie、防火墙等

# HTTP Flood (使用 web spider 抓取网站,以耗尽服务器资源)

确保只允许一个知名的引擎,如谷歌引擎或 bing 引擎爬你的网站

# DNS amplification attacks(DNS 放大攻击)

为了防止 DNS 反射攻击,可以使用反欺骗技术、负载均衡器或通过任播 IP 地址将攻击流量传播到其他服务器

# 参考

8 大前端安全问题(上) (opens new window)

8 大前端安全问题(下) (opens new window)

前端安全系列(一):如何防止 XSS 攻击 (opens new window)

前端安全系列之二:如何防止 CSRF 攻击 (opens new window)

DDOS 攻击的防范教程 (opens new window)

漫话:如何给女朋友解释什么是 DDoS 攻击? (opens new window)

GitHub 遭受的 DDoS 攻击到底是个什么鬼? (opens new window)

10 Major Types of DDoS Attacks and Prevention (opens new window)

浅谈 DDOS 攻击与防御 (opens new window)

防范 DDOS 攻击的 15 个方法 (opens new window)

你连 HTTPS 原理都不懂,还讲“中间人攻击”? (opens new window)

【面试篇】寒冬求职之你必须要懂的 Web 安全 (opens new window)

SQL 注入盘点专栏 (opens new window)

常见六大 Web 安全攻防解析 (opens new window)

最近更新: 4 小时前