关于接口 API 安全你需要知道的那些事
关于接口 API 安全你需要知道的那些事
前言
随着移动互联网的快速发展,智能手机已成为人们连接世界的重要工具。与此同时,隐私和安全问题也日益受到重视。从2021年某滴滴安全信息泄露事件开始,人们对信息安全的呼声和诉求越来越高。
在软件开发中,无论是APP还是各种访问终端的入口,最终承载交互数据的都是API。因此,API的安全性至关重要,它可以说是系统的守卫员,不容有失。
API安全常见问题
1. 接口被恶意调用
当系统的某些接口被攻击者或别有用心的人恶意调用时,可能会出现以下情况:
- 系统被狂刷短信
- 某个页面直接卡死,导致其他用户无法访问
- 系统服务器CPU瞬间飙升
- 平台内关联的其他应用也无法正常使用
为什么API接口会被恶意调用呢?经验来看,无非就那点,树大招风,你的产品被竞争对手盯上了,人家眼红了。
2. 接口数据被篡改
这也是一种常见的API安全问题。一个典型场景是,当你登录某个系统时,你的会话信息(如存在浏览器中的cookie信息)被别有用心者劫持,然后这个人拿着你的信息冒充你的身份去请求API的数据,甚至修改你的数据返回给你进行诈骗等目的。使用过Fiddler抓包工具的同学可以在自己公司的产品中模拟这个过程。
3. 接口敏感数据被窃取
通常在B端产品中,会对某些API返回的部分字段数据进行脱敏,比如手机号、邮箱等,以保证用户的信息隐私。尽管API层面对敏感数据做了脱敏处理,但敏感数据如果未进行加密处理,或加密的强度不够,或者没有安全的存储加密数据,以至于攻击者仍然能够获得敏感信息,进而攻击者可能利用此漏洞对客户端,或服务器发送特殊构造的数据,发出攻击,从而了解后台数据库表等信息,对系统安全构成威胁。这也就是接口敏感数据被窃取了。
4. XSS攻击
深究起来,XSS攻击更多偏向于前端这一层,但是对于一个能够提供充分安全保障的系统来说,API的对于参数的安全校验也是非常重要的一环,对于系统来说,应该确保核心API的业务对于所有的入参都应该是安全,可信且经过校验之后才能进行数据存储的。这样可以从源头上保障XSS攻击影响的范围进一步缩小。
系统层面的安全防护解决措施
在系统架构设计之初,系统安全一定是一个重要的考量因素被纳入到架构设计规划中,系统安全关乎着既关乎公司的生存,也关乎产品的盈利,更进一步说,更关乎着法律法规对公司的监管合规性依据。下图所示,为一个通用的微服务业务架构图。
从实践经验来看,安全在一个系统的架构设计中占据着举足轻重的地位,从上图来看,可以说,安全考虑在架构设计的每一环都有着落地的目标,拆开来看,具体如下所述。
1. 前端安全
涉及到前端安全的技术,比如:
- 页面表单的防重提交(功能上限制防刷的可能性)
- 接口请求前关键参数的校验,脱敏,XSS不安全字符的自动识别
- 使用参数加密,Base64处理,禁止明文传输
2. 系统级防火墙
防火墙本身具有较强的抗攻击能力,它是提供信息安全服务、实现网络和信息安全的基础设施之一。
防火墙对于一个互联网公司的重要意义毋庸置疑,尤其是金融类、银行类等B端产品,防火墙的作用可以说是不可替代的,尽管这个技术已经不是什么新鲜的东西,但基本上所有的软件公司在产品发布到线上环境之后,所有来自外部的请求,都会经过服务器厂商的防火墙,只有通过了防火墙这一层请求才能继续往下进行。
关于防火墙的作用,这里简单列举如下:
- 防止来自被保护区域外部的攻击,保护易受攻击的网络服务资源和客户资源
- 集中安全管理,通过集中的安全策略配置,以便统一管理和执行安全政策
- 防止信息外泄和屏蔽有害信息,执行安全检查,严格控制进出网络的数据,过滤和屏蔽有害信息,防止信息外泄
- 安全审计和告警,通过对网络存取访问进行监控审计,有效跟踪各类网络活动,及时发现问题和及时报警
3. 网关
关于网关,基本上所有的人都多少有一定的了解,网关在一个安全的系统架构设计中的作用,可以说是承上启下,至关重要,大体来说,从安全的角度来讲,主要体现在如下几个方面:
屏蔽真实的API地址
拿nginx来说,如果后端的接口真实地址是:/API/v2/user/get/1,为了确保接口安全,屏蔽真实的地址,通过nginx的反向代理之后,接口可能变成这样:
/platform/biz/API/v2/user/get/1。
负载均衡,均衡流量
从系统安全和系统可用性的角度讲,为了确保系统的高可用性,通常应用服务集群部署,这样可以避免单节点压力过大而造成业务高峰时系统不可用,有了网关这一层,就可以通过网关的配置动态实现负载均衡,以达到均衡流量的效果,从而对系统过载形成防护。
拦截恶意请求,定向黑白名单
以nginx来说,提供了可编程式的配置,通过编写脚本代码,对经过nginx的请求进行监控,尤其是对于那些恶意刷接口的请求,可以很好的进行识别,甚至可以在nginx这一层对那些恶意请求的IP,IP段进行黑名单的设置,从而对后台的服务进行第一层的安全防护。
限流
对一个系统来说,可用性已然成了系统是否稳定的考量因素的重要标准,当业务高峰期时,不管是外部的恶意请求,还是类似抢单这样的瞬间大流量来说,为了保障系统的整体可用性,必要的限流措施也是确保系统安全的重要手段,而网关作为承载系统流量的入口,在网关这一层做一定的限流管控是很有必要的。
API层面安全设计的常用解决方案
以上从架构设计层面聊了一下常用的安全防护措施,而作为系统对外提供数据来源的API接口,也就是系统的核心后台服务,可以说,关于API的安全考虑,可以说很多开发者在设计过程中尚未引起足够的重视。这里小编说一个有意思的现象,在小编过往的工作经历中,那些甲方公司最终对项目进行验收时,通常需要对整个源码进行安全审计,其中审计最容易出问题的地方,就是很多API接口的安全问题,比如XSS攻击,CSRF攻击,接口有被刷的风险……
接下来,针对上述谈到的问题,以及日常开发中对于API安全的一些规范性要求,一起探讨下在API安全设计的一些处理措施。
1. 控制API的访问边界
以当下流行的微服务来说,后台提供出去的API一定要规范访问边界,哪些接口可以暴露出去,哪些接口一定要通过鉴权才能访问,关于这一点,依照经验来说,做好下面几点即可:
- 接口设计之初,与前端同学约定好接口的使用场景
- 对外暴露且不需要鉴权的接口做好流控,避免被刷,比如有些登录接口中需要用到短信验证码的场景
- 对外暴露且不需要鉴权的接口做好严格的参数校验,避免XSS字符的入库存储
- 需要走鉴权的接口,最好走统一的安全校验逻辑,比如SDK或者内部封装的组件
2. 严格规范API的使用类型
对于某些比较大的平台来说,比如pass平台,通常都是十几个甚至几十上百个内部服务组成的,如此庞大的系统统一对外提供服务时,各应用服务之间必然存在着互相的调用,这些可以是dubbo调用,或者http的调用,通常不同的应用之间调用时,走rest接口非常多,同时,不同应用之间互相调用时,场景也是多样,有些需要认证,有些不需要,有些需要严格的认证,有些需要宽容的认证,这该怎么办呢?
针对上面的场景,这里可以考虑定义不同的API使用类型,针对不同类型的API,在调用的时候策略也不一样,具体实践来说,可以参照如下设计原则;
系统外部可调用的API
这种API,即内部应用和外部应用都可以调用的API,这类API的设计,通常需要通过一个统一的凭证颁发入口,调用者拿到这个凭证,在调用API时传过去,认证通过后,API给与数据响应,由于凭证是系统内部的服务颁发,可以认为是安全的,同时,如果更进一步的话,可以对凭证做有效期的设定,甚至是加密处理等措施。
系统内部可调用的API
即平台各个微服务应用之间调用的API,由于内部的应用在使用之前,都需要一定的注册或者其他的认证措施,对于内部的API调用来说,可以在API接口中添加关键参数信息识别即可,比如,在请求内部API的时候添加一个appName这样的标识,一旦API校验这个appName合法有效,就可以给与响应。
无需认证的API
比如请求系统的首页,或者上面谈到的请求短信验证码,再就是某些需要对接平台的外部第三方应用,这些第三方应用需要拿到一些非敏感的数据作为业务标识等,这种情况下,针对这样的API,在设计时,要做好关键参数的校验,接口防刷的处理,以及可信IP的识别。
3. API敏感参数加密处理
类似于登录,获取用户信息的API接口,一定要做加密处理,防止因会话劫持造成数据传输过程中敏感信息的泄露,关于加密,常用的加密方式包括:
- 密码的MD5加密,甚至可以混合盐值提高加密的安全等级
- 对称或非对称加密(根据业务需要选择)
- JWT,也是当下流行的一种轻量化的加解密方案
4. API请求header中混合特殊参数
一种常见的场景就是,前端请求API接口时,需要在请求的header中添加后台办法的token或者其他令牌等参数,而请求到达API之前(有的在API中做),解析并统一校验API请求中的header是否携带了这个参数,且有效的情况下才予以返回。如果你的API安全等级更高,可以考虑在请求header中混合其他的定制化参数,这也是一种有效的保护API的手段。
5. API自身的防刷措施
对于一个成熟稳定的系统来说,尽管请求在真正到达API时有各种防护措施,比如限流,恶意请求IP识别等统一的措施,但是作为打通数据后台到前台的最后一关,针对系统中的某些核心业务的API,还是有必要做针对性的接口防刷机制,具体来说,可参考下面的思路进行实施。
- API采用限流组件,或者引入开源限流SDK,或者自己编写限流算法工具包,对热点API进行限流
- 日志追踪,针对那些恶意刷接口的IP,记录在日志,并接入告警平台,定向的上报监控告警。
6. 尽量对请求参数进行封装
一般来说,从rest请求安全的角度来说,post请求的安全性要好于get请求,这是因为大多数情况下,get请求暴露在请求url中,而post请求的参数相对来说会隐蔽一些。这里给出的建议是,当查询请求参数超过5个时,可以对请求参数进行封装,然后将亲请求类型调整为post。
7. API参数校验
为什么这一点放在最后来说,小编认为这是大多数开发者能够想到但在实际工作中又不能做得很好的一点。参数校验可以说是API层面最后一道基础但是重要的安全保障了,但是在参数校验这个度的把握上,很多开发人员显得有些不知所措,这里小编提出下面几点建议以供参考:
区分API的重要程度
并不是所有的API都需要一大堆的参数校验,为什么这么说呢?要知道,参数对于一个系统安全的影响随着链路的传递是逐渐增加的,假如说一段xss的字符作为参数传入到API接口中,假如不做处理最终会入库,后面再查询出来渲染到页面时候,这个危害性就大了,影响的不仅是用户的体验,甚至会失去一个潜在的有价值的用户。
说到这里,相信大家能够了解,假如在save数据的接口中就能够识别非法参数,从而进行拦截的话,后续所有的麻烦都可以提前避免掉。从这个角度来说,一个通用的做法就是,针对那些需要保存表单的数据,或者是涉及到修改,删除之类的API,一定要做好参数的校验和控制。
不要过度对参数进行校验
看到过不少开发者在一个存储数据的接口中对参数进行了相当篇幅的代码校验,并不是说这样不好,而是需要区分一个度的问题,举例来说,有人在编写一个保存用户的API接口时,对用户名称做校验时,大概有几十行代码,涉及的规则如下:
- 校验账户中是否有特殊字符,比如$%这样的字符
- 校验账户名称长度是否超过限制
- 校验系统中是否有重复的账户名
- 校验账户名中是否有违禁的词
- 校验账户名中是否有多音字
- …
我就想不通了,一个账户名的校验需要搞那么多花样吗,开个玩笑,这当然不是我的过激行为,我要表达的意思是,API设计时,在考虑安全性的同时尽可能兼顾使用者的习惯,简化因参数校验带来的交互流程上的麻烦。
写在文末
安全无小事,这句话应该来说对所有的行业都适用。希望从事开发的伙伴们在日常开发中对系统安全多一份敬畏,从而少一些因安全事故带来的不必要的麻烦。当然,系统的安全性建设是一项长期的工作,需要自顶而下,做好长远的规划,并逐步落实并贯穿到日常的每一个开发、测试、运维以及实施过程中,这样这才是长久之计,与君共勉。
文章来源网络,