交易订单的重复提交虽然通常不会直接影响现金流和商品流,但依然会给网站运营方带来损害,如消耗系统资源、影响正常用户订单生成、制造恶意用户发起纠纷的机会等。倘若订单对象是虚拟商品,也有可能造成实际损失。订单重复提交的检查工作本应该由网站自身实现,而 iFlow 业务安全加固平台则可以为未实现这项功能的网站提供防护。


以某开源购物网站为例,攻击者能够轻松实现订单的重复提交。我们看看如何在不修改网站源代码的前提下,使用 iFlow 通过透明加入一次性令牌来阻止订单的重复提交攻击。

一、不检查订单重复提交的原始网站

原始网站系统没有检查订单的重复提交,攻击者可以简单地重复提交订单。

1.1 正常用户访问

已登录用户在选择购买一件商品后,进入到确认订单页面:

用户点击提交订单按钮后,网站回复订单已生成:

可以在我的订单列表中看到刚才的订单:

订单生成的交互过程反映在 HTTP 协议层面如下:

sequenceDiagram
participant 正常用户
participant 浏览器
participant Web服务器
正常用户->>浏览器: 选择购买商品
浏览器->>Web服务器: 请求:/index.php?s=/member/paymentorder
Web服务器->>浏览器: 返回:确认订单页面
浏览器->>Web服务器: 请求:/js/payment_orders/payment_orders.js
Web服务器->>浏览器: 返回:payment_orders.js
浏览器->>正常用户: 显示:确认订单页面
正常用户->>浏览器: 点击提交订单按钮
浏览器->>Web服务器: js发送AJAX:提交订单信息
Note over Web服务器: 系统生成正常订单
Web服务器->>浏览器: 重定向页面:订单已生成
浏览器->>正常用户: 显示:订单已生成

1.2 攻击者访问

攻击者使用 Burpsuite 工具作为浏览器和 Web 服务器之间的代理。

攻击者象正常用户一样选择商品和确认提交后,能够在 Burpsuite 中的 HTTP history 中找到这个提交订单信息的请求。攻击者右键点击 Send to Repeater 后进入 Repeater 标签页。

攻击者通过多次点击 Send 按钮来重复发出请求报文从而重复产生订单,并可以在我的订单中看到多个重复生成的订单,如下图所示:

HTTP 协议层面交互如下:

sequenceDiagram
participant 攻击者
participant 浏览器
participant 攻击工具
participant Web服务器
攻击者->>浏览器: 选择购买商品
浏览器->>Web服务器: 请求:/index.php?s=/member/paymentorder
Web服务器->>浏览器: 返回:确认订单页面
浏览器->>Web服务器: 请求:/js/payment_orders/payment_orders.js
Web服务器->>浏览器: 返回:payment_orders.js
浏览器->>攻击者: 显示:确认订单页面
攻击者->>浏览器: 点击提交订单按钮
浏览器->>攻击工具: js发送AJAX:提交订单信息
rect rgb(250, 128, 128)
Note over 攻击工具: 记录请求报文
end
攻击工具->>Web服务器: 发送AJAX:提交订单信息
Note over Web服务器: 系统生成正常订单
Web服务器->>浏览器: 重定向页面:订单已生成
浏览器->>攻击者: 显示:订单已生成
Loop 重复
rect rgb(250, 128, 128)
攻击者->>攻击工具: 发送已记录的请求报文
end
攻击工具->>Web服务器: 提交订单信息
rect rgb(250, 128, 128)
Note over Web服务器: 系统生成重复订单
end
Web服务器->>攻击工具: 返回响应报文
攻击工具->>攻击者: 忽略响应报文
end

二、iFlow虚拟补丁后的网站

我们在 Web 服务器前部署 iFlow 业务安全加固平台,它有能力拦截、计算和修改双向 HTTP 报文并具备存储能力,成为 Web 应用的虚拟补丁。在本例中,iFlow 在加载订单支付代码时生成并加入一次性随机令牌,在提交订单时检查这个令牌的存在。

2.1 正常用户访问

用户在访问确认订单页面时,浏览器自动加载处理订单支付的 JS 代码 (payment_orders.js)。iFlow 截获这段代码的响应返回,生成一个随机令牌保存在本地存储中,并修改 JS 代码将随机令牌加入到 AJAX 发送列表中。用户在点击提交订单按钮时,JS 代码发出 AJAX 请求将随机令牌随同订单信息一起发出,iFlow 截获请求,检查参数中的令牌是否与保存的令牌一致,并清除本地存储中保存的令牌。对于一个正常用户来说,它们一定是相同的,于是 iFlow 去掉令牌参数,将仅包含订单信息的请求发往 Web 服务器处理。

正常用户的 HTTP 协议交互过程如下:

sequenceDiagram
participant 正常用户
participant 浏览器
participant iFlow
participant Web服务器
正常用户->>浏览器: 选择购买商品
浏览器->>Web服务器: 请求:/index.php?s=/member/paymentorder
Web服务器->>浏览器: 返回:确认订单页面
浏览器->>Web服务器: 请求:/js/payment_orders/payment_orders.js
Web服务器->>iFlow: 返回:payment_orders.js
Note over iFlow: 生成随机令牌并保存
rect rgb(160, 250, 160)
iFlow->>浏览器: 修改:AJAX发送列表中加入令牌
end
浏览器->>正常用户: 显示:确认订单页面
正常用户->>浏览器: 点击提交订单按钮
浏览器->>iFlow: js发送AJAX:订单信息及令牌
rect rgb(160, 250, 160)
Note over iFlow: 与保存的令牌比对:通过
Note over iFlow: 清除保存的令牌
end
iFlow->>Web服务器: 提交订单信息
Note over Web服务器: 系统生成正常订单
Web服务器->>浏览器: 重定向页面:订单已生成
浏览器->>正常用户: 显示:订单已生成

2.2 攻击者访问

如前所示,攻击者记录下正常操作时的提交订单的请求报文,然后用工具重放这段报文。由于在第一次正常提交后,iFlow 已经清除了本地存储中保存的令牌,因此后续的重复提交被 iFlow 拒绝。

攻击者的 HTTP 协议交互过程如下:

sequenceDiagram
participant 攻击者
participant 浏览器
participant 攻击工具
participant iFlow
participant Web服务器
攻击者->>浏览器: 选择购买商品
浏览器->>Web服务器: 请求:/index.php?s=/member/paymentorder
Web服务器->>浏览器: 返回:确认订单页面
Web服务器->>iFlow: 返回:payment_orders.js
Note over iFlow: 生成随机令牌并保存
rect rgb(160, 250, 160)
iFlow->>浏览器: 修改:AJAX发送列表中加入令牌
end
Web服务器->>浏览器: 返回:payment_orders.js
浏览器->>攻击者: 显示:确认订单页面
攻击者->>浏览器: 点击提交订单按钮
浏览器->>攻击工具: js发送AJAX:订单信息及令牌
rect rgb(250, 128, 128)
Note over 攻击工具: 记录请求报文
end
攻击工具->>iFlow: 发送AJAX:订单信息及令牌
rect rgb(160, 250, 160)
Note over iFlow: 与保存的令牌比对:通过
Note over iFlow: 清除保存的令牌
end
iFlow->>Web服务器: 提交订单信息
Note over Web服务器: 系统生成正常订单
Web服务器->>浏览器: 重定向页面:订单已生成
浏览器->>攻击者: 显示:订单已生成
Loop 重复
rect rgb(250, 128, 128)
攻击者->>攻击工具: 发送已记录的请求报文
end
攻击工具->>iFlow: 提交订单信息+令牌
rect rgb(250, 128, 128)
Note over iFlow: 检查保存的令牌:无
end
iFlow->>攻击工具: 中断连接
end

2.3 代码

iFlow 内置的 W2 语言是一种专门用于实现 Web 应用安全加固的类编程语言。它介于配置和通用语言之间,具备编程的基本要素和针对 HTTP 协议的特有扩展,能为业务系统编写涉及复杂判断和动态修改的逻辑。

考虑到安全产品的使用者通常为非程序员,他们习惯面对配置文件而非一段代码。因此,W2 语言虽包含语言要素,仍以规则文件方式呈现,并采用可以体现层次结构和方便词法校验的 JSON 格式。

用 W2 语言实现上述虚拟补丁的代码如下:

[
{
"if": "REQUEST_FILENAME == '/js/payment_orders/payment_orders.js'",
"then": {
"execution": [
"TX.raw_token = md5(random())",
"SESSION.order_token@300 = TX.raw_token",
"TX.js_part = '\"' .. TX.raw_token .. '\"'",
{
"directive": "alterResponseBody",
"op": "string",
"target": "'leavemessage' : leavemessage,",
"substitute": "'leavemessage' : leavemessage, 'order_token' : ${TX.js_part},"
}
]
}
},
{
"if": [
"REQUEST_METHOD == 'POST'",
"REQUEST_FILENAME == '/index.php'",
"@ARGS.s == '/order/ordercreate'"
],
"then": {
"if": "SESSION.order_token",
"then": {
"if": "@ARGS.order_token != SESSION.order_token",
"then": {
"verdict": {
"action": "drop",
"log": "${@ARGS.order_token} is not equal to ${SESSION.order_token}!"
}
},
"else": [
"SESSIOIN.order_token = null",
{
"directive": "alterArgPost",
"op": "unset",
"name": "order_token"
}
]
},
"else": {
"verdict": {
"action": "drop",
"log": "${SESSION.order_token} is not exist!"
}
}
}
}
]

示例代码中有两条规则,分别作用如下:

第一条规则

当浏览器请求 payment_orders.js 时,iFlow 拦截响应报文。它首先生成一个随机令牌 raw_token 并将其存放在会话 (SESSION) 存储变量 order_token 中,然后修改处理用户提交订单的 AJAX 操作,将随机令牌加入到 POST 的发送参数列表中。

第二条规则

当用户执行提交订单时,JS 发出一个 AJAX 的 POST 请求,iFlow 拦截此请求。它检查会话 (SESSION) 存储变量 order_token 和参数中的 order_token,如果前者不存在或者两者不相等,即判定为非法请求。否则,将存储变量 order_token 清除,将请求参数 order_token 消除 (以免影响后端应用),然后发给后端 Web 服务器。

注意:上述会话中的 order_token 标志是保存在服务器端的 iFlow 存储中的,在浏览器端是看不到数据更无法进行伪造的。

三、总结

iFlow 使用两条规则在不修改服务器端代码的前提下,透明地实现了随机令牌的一次性发放和使用,避免了简单的重复提交。

当然,如果攻击者完全模拟用户正常操作,重复发起包含前后 2 次会话的攻击行为,则本文中的规则无法阻挡这种重复提交。但显然这种行为需要更复杂的攻击技巧而不只依靠简单地重放实现,何况,使用 iFlow 还能构建出更复杂的防护策略。(张戈 | 天存信息)

WEB安全新玩法 [8] 阻止订单重复提交的更多相关文章

  1. WEB安全新玩法 [1] 业务安全动态加固平台

    近年来,信息安全体系建设趋于完善,以注入攻击.跨站攻击等为代表的传统 Web 应用层攻击很大程度上得到了缓解.但是,Web 应用的业务功能日益丰富.在线交易活动愈加频繁,新的安全问题也随之呈现:基于 ...

  2. WEB安全新玩法 [5] 防范水平越权之查看他人订单信息

    水平越权是指系统中的用户在未经授权的情况下,查看到另一个同级别用户所拥有的资源.水平越权会导致信息泄露,其产生原因是软件业务设计或编码上的缺陷.iFlow 业务安全加固平台可以缓解部分场景下的水平越权 ...

  3. WEB安全新玩法 [3] 防护交易数据篡改

    在任何涉及交易的系统中,客户与商家之间的交易数据具有核心作用,如购买商品的价格.数量.型号和优惠券等.在客户挑选商品的过程中,这些交易数据逐渐形成:待客户提交订单时,交易数据被商家接收,形成双方认可的 ...

  4. WEB安全新玩法 [4] 防护邮箱密码重置漏洞

    大部分具有账号系统的应用都会提供重置用户登录密码的功能,常见方式之一是:用户输入自己的邮箱地址或手机号,应用向这个邮箱或手机号发送验证码,用户将收到的验证码输入应用中即可完成密码重置.这一过程容易因设 ...

  5. WEB安全新玩法 [2] 防范前端验证绕过

    用户登录,几乎是所有 Web 应用所必须的环节.Web 应用通常会加入一些验证手段,以防止攻击者使用机器人自动登录,如要求用户输入图形验证码.拖动滑动条等.但是,如果验证的逻辑仅仅在前端执行,是很容易 ...

  6. WEB安全新玩法 [6] 防范图形验证码重复使用

    在完成关键业务操作时,要求用户输入图形验证码是防范自动化攻击的一种措施.为安全起见,即使针对同一用户,在重新输入信息时也应该更新图形验证码.iFlow 业务安全加固平台可以加强这方面的处理. 某网站系 ...

  7. WEB安全新玩法 [9] 重置密码之验证流程防绕过

    一般来说,业务流程中出现多个操作环节时,是需要顺序完成的.程序设计者往往按照正常用户的操作顺序实现功能,而忽略了攻击者能够绕过中途环节,直接在后续环节上进行非法操作.iFlow 业务安全加固平台能够在 ...

  8. WEB安全新玩法 [10] 防范竞争条件支付漏洞

    服务器端业务逻辑,特别是涉及数据库读写时,存在着关键步骤的时序问题,如果设计或代码编写不当就可能存在竞争条件漏洞.攻击者可以利用多线程并发技术,在数据库的余额字段更新之前,同时发起多次兑换积分或购买商 ...

  9. Odoo 库存管理-库存移动(Stock Move)新玩法

    库存移动(Stock Move)新玩法 Odoo的库存移动不仅仅是存货在两个“存货地点”之间的移动的基本概念了,他们可以被“串联”在一起,可以用来生成或改变其对应的拣货单 (Picking).链式库存 ...

随机推荐

  1. python+selenium基础篇,文件上传

    1.百度查询图片,上传文件 2.实现代码如下: from selenium import webdriverfrom time import sleepdr=webdriver.Firefox()dr ...

  2. SpringAOP 原理解析

    什么是AOP? 1: 传统的OOP编程他的代码逻辑是一种自上向下, 而在这些自上而下的过程中会产生一些横切性的问题,比如说:日志信息,权限校验认证,事务等, 2: 这些横切性问题,往往与我们的主业务逻 ...

  3. 牛客网sql实战参考答案(mysql版):16-21

    16.统计出当前(titles.to_date='9999-01-01')各个title类型对应的员工当前(salaries.to_date='9999-01-01')薪水对应的平均工资.结果给出ti ...

  4. Java8 Lambda表达式、Optional类浅析

    1.概念 Lambda是一个匿名函数,可以将其理解为一段可以传递的代码(将代码像数据一样进行传递)可以写出更简洁.更灵活的代码.作为一种更紧凑的代码风格,使得java语言的表达能利得到了提升. 2. ...

  5. LeNet-5网络搭建详解

    LeNet-5是由Yann LeCun设计的用于手写数字识别和机器打印字符的卷积神经网络.她在1998年发表的论文<基于梯度学习的文本识别>中提出了该模型,并给出了对该模型网络架构的介绍. ...

  6. bzoj1925 地精部落

    神题! 地精部落 内存限制:128 MiB 时间限制:1000 ms 标准输入输出     题目描述 传说很久以前,大地上居住着一种神秘的生物:地精. 地精喜欢住在连绵不绝的山脉中.具体地说,一座长度 ...

  7. Kali下切换JDK版本

    Kali下自由更换JDK版本 今天在学习了一下CobaltStrike之后,打算在Kali上本地搭建一个服务器端, 查看了一下Kali的JDK配置发现版本是13.X的,然而CobaltStrike最好 ...

  8. Unity不规则按钮点击区域(UGUI)

    文章目录 一. 前言 二. 最终效果 三. 实现 1.创建UICamera 2. UIPolygon节点 3. 编辑碰撞区域 5. 运行测试 6. UIPolygon代码 一. 前言 游戏开发中,可能 ...

  9. 1、mysql基础入门(2)

    1.4.常用非关系型数据库产品介绍: 1.Memcached(key-value)数据库:

  10. mysql大量数据分页查询优化-延迟关联

    所有的php初学者都应该知道,mysql的分页语句写法如下: 1 select * from a limit (page-1)*page_size,page_size 而当这语句分页到一定程度时,例如 ...