- 背景
- 产品设计
- 解决什么问题?
- 举个栗子
- 问题分析
- 接口调用服务化过程
- 问题1:如何增加参数的分析难度?如何增加参数的伪造难度?
- 问题2:如何增加构造请求的难度?
- 接口调用服务化过程
- 解决方案
- 解决以上问题,有如下三种方案
- 设计点一:防止请求参数伪造
- 设计点二:防止脱离容器
- 设计点三:防止请求重放
- 整体防御流程
- 解决以上问题,有如下三种方案
- 解决什么问题?
- 问题反思
从2019年开始主导一些Qunar业务安全相关的基础安全产品,如设备指纹、环境检测以及接口防护等,对于验证码也有系统维护和相关破解经验。其中也有许多自己觉得还算可以(能够满足业务)的设计,当然也有一些实践后发现不足的设计。写这篇文章的目的是想要把其中的一些思考和经验教训和大家分享。
产品设计这篇文章我想以接口防护作为案例,来讲述设计安全产品时所需要的思考的要点。
解决什么问题? 举个栗子ip查询请求是从ip138.com网站的查询首页中发送出去的。通过GET请求拼接上查询参数
?ip=123.152.159.88&action=2
如果大家对逆向工程有一些了解,这时服务化的最优解就是通过接口调用(可以想象成使用postman发送请求)。直接通过接口调用请求服务是成本最低的作弊方式,如何防止该类型的作弊方式呢?
url:https://www.ip138.com/iplookup.asp?ip=123.152.159.88&action=2
问题分析
接口调用服务化过程
Step1:抓包
Step2:分析请求参数
Step3:伪造请求参数
Step4:构造请求
以上四个阶段,我们能够防御的点是分析请求参数阶段、伪造请求参数以及构造请求阶段。问题就转化为如何增强这三个阶段的难度。
问题1:如何增加参数的分析难度?如何增加参数的伪造难度?抛开端上加固(混淆、反调试等)不谈,仅仅讨论参数本身。
我能够想到的就是3种方式分别是:
(1)参数加密;
(2)参数加签;
(3)特定含义的参数;
无论以上的哪种方式,其本质就是使参数无法被猜测。而使用哪种取决于系统设计中哪种接入更方便、更友好。
问题2:如何增加构造请求的难度?除了增加参数本身的伪造难度,还可以检测当前构造请求的环境,检测当前是否处于目标的容器中。
解决方案 解决以上问题,有如下三种方案(1)防止请求伪造;
(2)防止脱离容器;
(3)防止请求重放;
设计点一:防止请求参数伪造攻击者能够任意地篡改请求参数。
(1)将请求参数进行拼接。(如key1=value1&key2=value2… )
(2)对请求参数进行签名。(拼接SecretKey,然后对其进行MD5运算)
(3)请求参数中携带sign值。
在做此处设计时,还会遇到很多细节问题,如get请求参数如何处理?post请求参数如何处理?参数顺序如何处理?中文字符如何处理?不同运行平台浮点型数据如何处理?等等
设计点二:防止脱离容器防止请求脱离浏览器,比如:直接使用postman或服务代码直接发起请求。
(1)本地生成标识ID
(2)服务器下发标识ID
(3)容器特征收集
设计点三:防止请求重放攻击者多次重复使用相同请求参数。
(1)通过时间戳记录当前请求参数生成时间。
(2)通过唯一随机字符串nonce,为每一个请求生成唯一标识符。
整体防御流程 问题反思安全产品的设计除了需要考虑安全性外,还需要考虑产品的易用性。如方案中的设计点一防止请求参数伪造,其中就需要对请求参数进行签名,要求请求参数传入防御模块,并携带签名请求业务服务,这就对业务接入要求非常高,要保证传入前端防御模块的参数与传到业务服务后端的参数完全一致,才能保证签名的正确性,在安全开发过程和业务接入过程都需要反复地进行联调验证,这会消耗大量的开发联调时间。
我们在设计安全产品时,不仅需要从安全角度考虑产品的安全性,更要从软件工程的角度考虑产品的易用性,甚至有是有安全性可以向易用性让步。