Browse Category: 后端

好刚: 视频介绍XXE 漏洞

视频讲解XXE 漏洞,懂点关注XXE 漏洞的攻击原理和流程流程,最后给出XXE 漏洞的防范措施

你好,我是好刚,这一讲我们来了解XXE 漏洞 (XML External Entity Injection)。

1. 背景

前两天微信提供给商家的java SDK 被发现存在XXE漏洞,通过这个漏桶,攻击者可以获取服务器上的代码文件内容,包括各种公私秘钥等。那获取这些信息以后,攻击者就可以做很多事情了,其中就可能包括媒体宣传的“0元也能买买买”。今天我就来带你了解下这个漏洞。

2 XXE 漏洞原理

这次的漏洞是XXE漏洞,全称叫:XML 外部实体注入(XML External Entity Injection)。

首先是XML,XML 是一种标记语言,可以用来定义数据类型,定义好的数据可以方便的在系统间传输和使用。XML文档结构可以分为XML声明、文档类型定义(DTD)、文档元素,其中DTD 是可选的,漏洞就是在解析DTD 时产生的。

2.1 DTD 与实体

这里DTD(文档类型定义)的作用是定义XML文件中有哪些元素、元素的属性、以及元素包含的内容等等,DTD 可以在 XML 文档内声明,也可以从外部引用,从外部应用时需要使用 SYSTEM 标识。

DTD 中可以定义实体,在内部DTD 中声明的实体称为内部实体,外部DTD 中声明的称为外部实体。实体就像一个常量,可以将一串普通文本定义为一个实体,就可以在XML 通过实体快捷的引用这段描述。

对实体的定义可能比较抽象,我们先来看下内部实体示例,来看下实体到底是什么。

在解析XML时,实体将会被替换成相应的引用内容,经过解析后,XML 编程这样:

2.2 外部实体

在DTD中,还可以使用 SYSTEM 标识,从外部url 和本地file 文件中引入外部实体。

这里实体将会被替换成相应的引用内容,也就是/etc/password。正是因为外部实体可以解析url 和本地文件,这才使得XXE 攻击成为可能。我们继续往下看攻击者是怎么样基于这一点实现攻击的。

3 XXE漏洞攻击流程

这里以利用XML 解析外部实体的特性读取服务器文件信息为例,介绍下整个攻击流程。

  1. 假设受攻击者的web 服务器中存在POST接口: 127.0.0.1/wxpay/callback,这个接口中接收xml 字符串做参数,并且会对xml 参数进行解析。

  2. 构造请求数据,请求的xml 内容如下:

/etc/password 是要窃取的对象,password 保存了用户列表,这个文件太重要。

http://127.0.0.1:9000/xxe.dtd 是攻击者服务器中的dtd 文件,内容如下:

  1. 受攻击者的web 服务器解析收到的xml 参数时,会按如下步骤进行解析

第一步,读取 file:///etc/password 的内容,作为 % file 实体的值
第二步:请求攻击者的外部DTD,通过 http://127.0.0.1:9000/xxe.dtd 会拿到恶意的DTD 文件。
第三步:解析恶意DTD 文件 xxe.dtd,这时会请求 http://127.0.0.1:9000/attack/%file; ,并且带上 /etc/password 文件里面的内容作为路径参数,这个请求会在攻击者服务器 http://127.0.0.1:9000 中留下请求记录,这样攻击者就拿到了 /etc/password 文件的内容。

这个示例中,窃取的是 /etc/password 文件的内容,实际上只要有文件读权限,就可以获取服务器中任何文件的内容,比如代码里面的秘钥。

3.2 支付漏洞是怎么回事

了解xxe 漏洞原来,我们来看下这次漏洞对微信的影响到底是什么样。

首先来看一个简略版的支付流程:

  1. 正常用户选择好商品,请求商家服务器进行下单,商家计算付款金额后显示支付页面,提示用户支付
  2. 用户根据支付金额触发微信支付,注意,这个时候用户会进入微信支付的页面,与微信进行交互,并且完成支付。
  3. 微信用户将完成支付的消息回调给商家服务器,通知商家用户已经支付,商家确认订单和支付金额后也将订单状态改为已付款。
  4. 然后提示用户付款完成,跳转到购买成功的页面

当然实际的支付流程比这复杂得多,感兴趣的同学可以给出下方参考资料找到详细文档。

这里产生支付漏洞的位置是在第3 步,微信通过请求商家服务器,通知商家用户已经支付,这个接口的代码一般会使用微信的SDK 进行开发,这个SDK 里面有段代码在解析XML 请求数据时,产生了漏洞,这就是这次攻击的由来。

4. 漏洞的解决

通过介绍,我们知道XXE 漏洞之所以能够存在,本质上在于在解析XML的时候,可以与外部进行通信,使攻击便成为可能。那解决该漏洞的办法也非常简单,就是禁止XML 解析时可以访问外部实体,代码上需要明确调用禁用解析外部实体的函数。

java 语言

php 语言,需要注意PHP 5.3 以后的版本默认是不会解析外部实体的,这就极大降低了受影响的可能性,当然也有函数明确禁止。

5. 总结反思

5.1 危害不只是不花钱

最后总结下,在很多媒体的报道中,都强调通过这个漏洞,攻击者不花钱就可以获得商品。不过很多大型购物网站,都会有对账系统,会定时将网站的用户订单数据与微信后台的数据进行对比,出现不一致时会及时报警,所以这个漏洞在这方面的影响可能并没有想象的那么大。

另外除了不花钱获取商品,攻击者更可能造成的危害是,通过漏洞获取到了应用服务器上的代码、数据和配置登录信息,然后再根据这些信息进行进一步的攻击,这个危害更严重。

5.2 检查提供XML 支持的接口

XXE 漏洞是由于XML 解析器默认不会禁用对外部实体的访问,因此只要我们的系统对外的接口有使用xml做请求参数,并且在解析xml参数时,没有禁用对外部实体的访问,那也容易掉进XXE漏洞的坑里。建议大家最好检查一下自己的应用中是否有类似的漏洞,及时修复。

5.3 使用JSON

最后,用于数据传输的格式还有JSON,相比XML,JSON 更加轻量和现代化,不像XML 有那么复杂的数据格式,所以JSON 更适合于系统间的数据交换,所以如果可以,建议考虑多使用JSON。

安全无小事,XXE 漏洞就介绍到这,你听懂了吗,听懂了就来关注转发下,让身边的同事也了解下。我是好刚,好钢用在刀刃上,我们下期见。

参考资料

好刚:视频介绍限流算法

视频介绍限流算法,分析漏桶算法和令牌算法的应用场景,算法原理和算法实现方法

你好,我是好刚,这一讲我们来了解限流算法 (Rate Limiting Throttling)。

1. 应用场景

首先我们看一个典型的应用场景,比如在商品抢购的场景里面,可能会有百万级别的用户请求我们的抢购接口,这个时候如果不做任何保护措施,服务器就会承受很大的处理压力,请求量很高,服务器负载也很高,并且当请求超过服务器承载极限的时候,系统就会崩溃,导致所有人都不能访问。为了保证抢购服务的可用性,一个常用的办法是对秒杀请求进行限流,拦截掉大部分请求,只允许一部分请求真正进入后端服务器,这样就可以防止大量请求造成系统压力过大导致的系统崩溃,从而保护服务正常可用。这里限流的常用算法有漏桶算法和令牌桶算法。

2. 漏桶算法

我们先来看漏桶算法(Leaky Bucket),先想象有一个木桶,新请求就像水滴一样,不断地滴进来,水滴进来的速度是不确定的,有时会快一点,有时会慢一点,同时桶底下有个洞,可以按照固定的速度把水漏走,如果水进来的速度比漏走的快,桶就会满了,桶满了水就会漫出来,对应的就是拒绝请求。

漏桶算法的主要特点是可以平滑网络上的突发流量,请求可以被整形成稳定的流量。

算法伪代码如下:

3. 令牌桶算法

我们再看下令牌桶算法(Token Bucket)。也是先有一个木桶,系统按照固定速度,往桶里加入Token,如果桶已经满了就不再添加。当有请求到来时,会各自拿走一个Token,取到Token 才能继续进行请求处理,没有Token 就拒绝服务。

这里如果一段时间没有请求时,桶内就会积累一些Token,下次一旦有突发流量,只要Token 足够,也能一次处理。所以令牌桶算法的特点是允许突发流量。

我们看一个例子,看看令牌桶如何允许突发流量,假如令牌则按照每秒5 个的速度放入令牌桶,桶中最多存放20 个令牌,那系统可以支持两种类型的请求流量,一种是允许持续的每秒处理5 个请求,第二种是每隔4 秒,等桶中20 个令牌攒满后,就可以处理一次有20 个请求的突发情况。

算法伪代码如下:

4. 两种算法比较

最后我们对比下漏桶算法和令牌桶算法。其实在实现上,两种算法是效果一样但方向相反的算法。

漏桶算法是请求流入的速度不确定,有时快有时慢,是存在突发情况的;但是请求流出的速度是固定的,它是流入会有突发情况,但是流出速度固定。

令牌桶算法就是固定的Token 流入速度,一个Token 代表一个请求可以被处理的机会;当系统有一段空闲时间之后,桶内有足够的token,这样可以处理突发的请求流量,它是流入速度固定,但是流出不固定。

总结下特点:漏桶算法因为流出速度固定,可以用来整流,无论你流入速率多大,我都按照固定的速度去处理。令牌桶算法的特点则是,支持突发情况,两种算法在实际使用时,应该根据具体场景灵活选用。

限流算法就介绍到这,我是好刚,好刚用在刀刃上。如果讲解对你有帮助,那就请你帮忙转发吧。

5. 令牌通算法实现

PHP 实现

参考资料

toml 简介

toml

1. 简介

编程中经常需要使用配置文件,常见配置文件有用INI, XML, JSON, YAML 语言编写,它们的表达力越来越强,同时书写便捷性也在不断提升。

TOML 全称: Tom’s Obvious, Minimal Language, 对应中文为 Tom的(语义)明显、(配置)最小化的语言。

TOML 是前GitHub CEO, Tom Preston-Werner,于2013年创建的语言,其目标是成为一个小规模的易于使用和阅读的语义化配置文件格式。

TOML 被设计成可以无歧义地映射为哈希表, 而编程语言中都会有类似哈希表的数据结构,从而可以很容易的被各种语言解析。

需要注意: 此规范当前为0.4 版,仍然会发生很多变化。

2. 语法

toml 语法规范

  • TOML是大小写敏感的。
  • TOML文件需要是UTF-8 编码。
  • 空格是指制表符(0x09) 或空格 (0x20)。
  • 换行符是指LF(0x0A)或CRLF (0x0D0A)。

配置示例

3. 变量类型

  • 字符串
  • 整数
  • 浮点数
  • 布尔
  • 日期
  • 数组
  • 嵌套表
  • 内联表
  • 表数组

注释

用符号#来表示注释:

键名

键值对左边是键,右边是值。键名和值周围的空格都将被忽略,键、等号和值,一定要在同一行(有些值可以多行表示)

键可以是裸键,或者由双引号包括,不可以是单引号。

裸键 仅包含字母、数字、下划线和破折号。

引号键 遵循基本字符串的规则,可以使用更广泛的键名。除非有必要,否则建议使用裸键。

字符串

有四种表示方法:基本字符串、多行基本字符串、字面量和多行字面量。

基本字符串 双引号括起来的任意字符串,包含双引号、反斜杠和控制字符等转义字符。

多行基本字符串 三个双引号括起来的字符串,允许换行,所以可以将很长的字符串分成多行。

注意: 行尾存在\ 时,将会删除当前位置到下个非空字符或结束界定符之间的所有空格(包括换行符),该特性可以用于编写长字符串。所有的转义字符在多行基本字符串有效。

字面量字符串的特点是不允许转义,有基本字面量字符串和多行字面量字符串。

字面量字符串 是被单引号包含的字符串,跟基本字符串一样,它们一定是以单行出现:

因为不支持转义,所以字面量字符串里面没有办法写单引号。但是可以在多行字面量字符串中使用。

多行字面量字符串 被三个单引号括起来的字符串,允许换行。

紧跟起始界定符的换行符会被剪掉。界定符之间的所有其他内容都会被按照原样解释而不会被转义。

对于二进制数据,建议你使用Base64或其他适合的编码,比如ASCII或UTF-8编码。具体的处理取决于特定的应用。

整数

整数是没有小数点的数字。正数前面也可以用加号,负数需要用负号前缀。

对于大整数,可以用下划线提高可读性。每个下划线两边至少包含一个数字。

前导零是不允许的。也不允许十六进制(Hex)、八进制(octal)和二进制形式。

TOML 中不能表示诸如“无穷”和“非数字”,不能用一串数字表示的值。数字范围是64位从−9,223,372,036,854,775,808 到9,223,372,036,854,775,807。

浮点数

一个浮点数由整数部分(可能是带有加号或减号前缀的)和小数部分和(或)指数部分组成的数。如果只有小数部分和指数部分,那么小数部分必须放在指数部分前面。

小数部分是指在小数点后面的一个或多个数字。

指数部分是指E(大写或小写)后面的整数部分(可能用加号或减号为前缀)

和整数类似,你可以用下划线来提高可读性。每个下划线两边至少包含一个数字。

数据精度为64位 (double)。

布尔值

布尔值是小写的true和false。

时间日期

时间日期是RFC 3339中的时间格式。

数组

数组是由方括号包括的数据类型,元素由逗号分隔,元素的数据类型不能混用(所有的字符串均为同一类型,但是整形和浮点型是两种类型)。

数组可以写成多行,解析时会忽略空格和换行符。结束括号之前可以存在逗号。

表(也被称为哈希表或字典)是键值对集合,且键值对是无序的。表名由方括号括起,自成一行。

表的范围是在表名之下,直到下一个表或文件尾(EOF)之间都是该表的键值对。

表和数组相区分,数组里只有值。

嵌套表

使用点(.)来表示嵌套表,点前面的部分属于父表,点后面的部分属于子表。

等价于如下JSON格式:

编写时,你可以不用定义每一层父表(super-tables)。

只要父表没有被直接定义,而且没有定义特定的键,你可以继续写入。

你不能多次定义键或表。这样做是无效的。

被点分隔部分周围的空格都会被忽略,但是最好不要使用任何多余的空格

所有的表名和键一定不能为空

内联表

内联表提供一种更紧凑的语法来表示表,内联表是由大括号{}括起来的,在大括号内可以存在零个或多个逗号分隔的键值对。

内联表里的键值对跟标准表里的键值对形式一样并且允许所有的值类型,包括内联表。

内联表一般以单行出现。不允许换行符出现在大括号之间,除非是包含在值中的有效字符。
即便如此,也强烈建议不要在把内联表分成多行。如果你有这种需求,那么你应该去用标准表。

对应标准表定义:

表数组

表数组使用双中括号包裹表名,使用相同双括号名的每个表都是数组中的元素。表的顺序跟书写顺序一致。没有键值对的双括号表会被当作空表。

等价于如下JSON格式:

你也能创建内嵌的表数组。只需要对子表使用相同的双括号语法就可以。

上面的TOML对应于下面的JSON格式:

PHP toml 解析演示

安装解析库

解析示例

资料