OWASP API Top 10解读|首届API安全管理大会

演讲全文:

先自我介绍一下,我叫肖文棣,是AWS认证的解决方案架构师及安全专家,也是 OWASP技术社区广东分会的负责人。今天为大家介绍一下我们OWASP以及OWASP API Top 10,然后再针对于 OWASP API Top 10 给大家分享一些我对 API 安全的思考。

现在是 API 的时代,大家都说DevOps 、说云原生。那么说到云原生,他们中间一个很重要的就是微服务,微服务的基础就是 API ,微服务就是 restful API 。无论从银行、零售运输、物联网、自动驾驶和智能城市都需要 API 提供的数据集中数据,包括我们很敏感的 PII 的数据,个人识别数据以及对业务很敏感的业务核心数据。

最近看到一个新闻,某银行因为安全的处置不慎被罚了 50 万,有从业人员也被竞业。而且我们国家现在也出台了很多的法律,包括网络安全法、数据安全法、个人隐私保护法,所以对于数据的保护大家就要尤其谨慎了,特别是 API 。然后前段时间某购物平台也有十几亿的数据通过 API 泄露出去,所以说 API 的安全是非常重要的,大家一定要引起重视。

那么 OWASP API Top 10 是怎么评出来的呢?它是跟OWASP Top 10  是一样的逻辑,是根据可利用性弱点、普遍性弱点、可检测性、技术影响、业务影响进行综合评分后得出来的。比如说我在业界收集了 100 个问题或者 100 个风险点,评分哪个是排得最全的,那就是 Top 1  ,以此类推。

OWASP API Top 10包括哪些?

第一个叫做失效的对象级授权。什么叫对象?我们说 restful API都是基于数据,而以前我们说的 API 都是基于 shop ,基于动作,比如说 get 一个什么方法之类的。现在 restful它是基于数据的,比如说一个用户就会产生四大原语 get、post 、put、Delete。对象级的授权说的就是他每一个对象和对象之间它组合起来的授权是怎么样的。

第二个,失效的用户身份认证。大家可能对认证不是非常的清楚,甚至认为认证和授权是一样的,或者你的身份认证是怎么样的?一个身份认证是一个普通的密码还是基于 token ?

三是过度的数据暴露。例如本来这个 API 只想给用户三个点的结果,但没有设计好就可能是把整个数据所有的点都暴露出去了。

四是资源缺失和速率限制。比如说你的 API 可能希望一个 IP 最多每分钟调用 5 次,如果没限制,那我突破了呢?比如说 10 个 IP 调用 100 次行不行?或者一个 IP 我通过一些批处理也好,通过一些命令行也好,我能不能突破这个限制?因为任何一次调用实际上对于我们后台来说如果都要处理的话,公司就要付出成本,如果别人对你调用无数次,就会对你产生类似DDOS攻击的行为。

接下来还有失效的功能级授权。API 有几个原语:get、post 、put、delete、patch、head。你可能只对 put 进行了授权,对其他都没进行处理的话,特别是对patch、head有没有进行处理?如果没有,别人就有可能通过 patch和head 得到一些他不应该得到的数据。

第六是批量分配。也就是本来应该只能是能够看某个人的某条信息,但结果我直接用了一个 users ,我没做任何授权,就把所有人的用户都返回回去了。

还有安全配置错误。这个在OWASP Top 10 也经常在说。比如说你装了一个tomcat/ 装了一个nginx,然后用的都是默认的设置,默认设置是不是有可能是默认的密码?默认密码是不是很容易就被人家给破解了?

第八就是注入。实际上 API 它也是一个软件,它也是个应用,OWASP Top 10 经常说的注入风险包括SQL注入、XSS、XXE。接下来是资产管理不当。包括 API 有很多的version。大家都知道版本经常有 V0.1/V 0.2V1.0/V1.5,有可能 V1.5 的东西你做了保护,但老的那些version有没有管理好?有没有升级还是已经淘汰了?还是已经完全忘记了?或者是根本不在你的资产列表里面?

最后一个就是日志和监控不足。现在OWASP Top 10自 2017 年那个版本开始,就把它列到OWASP Top 10里面去了,大家也越来越认识到日志监控不足的危害。比如说我有一个系统被攻陷了,我压根就不知道。好像是美国的一个安全的专家说过,这个世界上就两种系统,一种是系统被攻陷了,一种是我被攻陷了但我不知道,所以说日志和监控就会非常的重要。

下面我们再展开每一条都详细说一下。

  • 详解 OWASP API Top 10及预防思路

首先看一下失效的对象级授权。对象级授权就是可能两个对象互相之间有关联,但是你可能考虑了 1 没考虑2,那么有可能 1 和 2 混合起来的时候就产生你想象不到的后果。我们来看一个例子,比如我允许别人去取我的用户的列表,也允许别人取我的商户的利润列表,如果我两个混合起来的时候,我是不是可以把所有的用户的所有的利润表都获取了呢?或者说有可能我真正的本意是允许知道商户列表,但是我是只我允许的人才能看我的利润表。但是如果你没做这个控制的话,那我是不是把双量放到里面去,它就可以获取出来了?还有监控可穿戴设备同样也是的,比如说 HTTP patch 里面带了一个 user ID ,这个 user ID 我如果你像他现在是一个54796?那我是不是可以写个 batch 命令来批编立它?比如说我换成 54154797 行不行?54780 行不行?这个就是要去综合利用。API 的安全实际上很多时候跟授权有关的,特别是一个 API 和另外一个 API 之间,如果混合起来使用的时候,它会产生我们意想不到的一些后果。

那么我们怎么预防呢?那就是基于用户策略和继承关系实现适当的授权。这里说我们登录的时候是一个用户对吧?那么我们访问这个数据属于是另外一个用户,他们用户之间有没有关联关系,允不允许看呢?这就要在权限设计上就去考虑这一点。还有接收用户输入的数据库中应该授权他有没有权限看,也就是说一定要区分开登录用户和你操作的数据的用户,他不是一样的,你登录了不一定就认为允许你去看。还有建议使用不可预测的GUID 来作为信息记录的 ID 。就刚刚说的,你如果用的是12345,那就很容易遍历了,你用的是 GUID 的话可遍历性就大大降低了,还有通过测试来授权。

第二个,失效的用户身份验证。那么我们的身份认证是怎么做的呢?很有可能正常的登录做了,但你的忘记密码做了没有?重试密码做了没有?他们可能都是不同的 API 或者说他是 API 的不同的表现。可能说很多时候包括我们去看那些白帽子挖的漏洞,很多人关心的是我登录的认证,但是我发现很多白帽子有可能要的就是如果重置密码怎么样,如果忘记密码又是怎么样?他可能通过别的方法去破解你的用户的身份认证。然后是凭据填充。如果是用简单的用户名密码,我是不是可以写个脚本就可以批量处理呢?对那些用户比如说尝试了五次之后,你就把用户锁住?类似的还有 SMS 的验证码,就是我们经常说的双因素认证,拿着一个短信验证码是不是一次有效呢?还是无限次可以试?这些都是问题。

那我们怎么预防呢?首先要确保你 API 认证的工作流应该是一致的,而且都要考虑到。然后要问工程师有没有遗留工作流,这个就比较难问了,你可能问他也不知道,因为他有可能他认为他是没有的,但实际上真正用起来的时候他是保证不了的。

还有一点很重要,不要在认证、凭据生成、密码存储方面自创算法,要使用标准的算法。这是为什么呢?经常有人说我为了体现我的水平,我就自己搞一个类似加密的东西。但实际上你那个算法能不能被破解?是不是足够安全的?你是要证明的。比如说以前的MD 5已经被证明是不安全了,但是 MD 5 如果没被证明之前它就是安全的。所以还是要用标准的算法,比如说 AES 256 还是比较安全的,还有 SHA512也比较安全的。

还有凭据重置、忘记密码端应被视作认证端点,在暴力破解、请求频率限制和锁定保护上同等对待。大家可以参考一下OWASP Authentication Cheat Sheet,里面讲了很多的跟认证相关的怎么处理的措施。还有一个是对于一些非常重要的 API 可以考虑双因素认证。对于非常重要的动作,可以考虑要求重复认证,而不是说仅仅带个 token 过来就可以。比如说我要做一个大笔的转账,那我可能要求他二次认证,而且还要防暴力破解,还有账户锁定。账户锁定也是一个双刃剑,用的好的时候比如说别人同样一个用户,他四五次你把他锁了。那么如果我知道你很多用户我恶意发起这种锁的操作,也可能对你产生类似 DDOS 一样的攻击,你的很多用户可能就直接不能用了。

还有 API key 大家都知道,经常它是用于用户认证,而且 API key 有很多人可能是误用的, API key 本身你可能认为它应该只是一个 use name。实际上现在主流的做法是 API key 加 API key 的一个 SecretKey \\产生类似用户名和密码产生一个 token 来进行认证,而不直接用 API key 来认证, API key 等同于类似 user name 而已。

第三个是过度的数据暴露。实际上最容易暴露的是我们写代码的时候,经常把一个对象完整的可能用 to JSON 或者 to string 或者直接把你对象里面的所有内容一次性都暴露出来了。

那我们再看看他可以怎么来预防。第一,不要依赖于客户端来过滤敏感数据。比如说银行,对于那些身份证、银行账号中间要加星号,你不要依赖于客户端来帮你加星,一定要在你的后端做处理。任何客户端都是不可信任的,因为中间可以拦截你的数据,我怎么改都可以。对于 API 的响应一定要确保只包含合法数据。什么叫合法数据呢?就是只包含他应该知道的数据,而不是什么数据都丢回去。

然后是在开放一个新的API 端点前,后端工程师应当反复确认 “谁才是真正的数据使用者?”。这个就比较难做到了,因为后端工程师他可能也不知道,但是我们可以要求他推广最小权限的原则。我们知道这个时代就类似断舍离一样,少是好,而不是多是好。以前我们业务经常去收集用户的数据,基本上什么数据都想收集回来。但现在基于这么多的法律,收集回来你能保护得住他吗?出问题怎么办?所以说我们就应该只允许提供我们应该访问的数据,而不是什么数据都返回回去。

还有要避免使用to_json() 和to_string()之类的通用方法,而是选用你真正想要返回的特定属性;还有应用存储那些敏感数据一定要去处理。如果你的系统是处理了敏感数据的,你一定要有分级分类,一定要对应的合规。还有执行schema-based响应验证机制作为额外的安全措施。实际上就是检查数据类型,特别是把数据引入到第三方去用的时候,这是防止一些额外的操作。

第四个,资源缺失和速率限制。就是说无需认证,单一请求就可以发多个并发没做数据验证。特别是在上传 post 命令的时候是最多的,比如你没有限制图像的大小、文件的大小或者说数量的大小。还有看检索用户现在不是分页的,你预计他都是一页 100 条的,那么如果他写个 9999 万条,你能不能处理这个,这些都是要去做限制的,都是在设计中都要去考虑的。

怎么进行预防?第一个, Docker可以轻松地限制内存、CPU、重启次数、文件描述符和进程。如果使用了微服务,是基于容器去做的,你的容器一定要做资源的限制。因为有容器跑起来它是需要有个基本的内存。实际上容器它是类似一个小型的操作系统,它上面会跑一些最基础的操作系统,接下来才是跑你的应用,你的应用不能把你所有的内存 CPU 都耗光,你一定要有个限度。也要对 API 的频率做限制。现在都有要求对于某个 IP 限制他每分钟访问 5 次,这是基于业务的,因为我们 API 最终的是卖给我们的客户,当然也有可能是提供的可以给前端去用,所以说一定要有做限制的,而不是说无限的。而且如果你出现了这种突破限制的话,应该要及时告警,这就涉及到最后会说的监日志和监控了。

还有服务器端字符串查询要做验证,就是不信任于过来的任何的输入。然后要验证所有的输入和参数的最大数据量,所有的输入都不可信任。预期中前端是说他只能是 10 兆的,但是如果我不要用前端,我直接发 API 请求,我发个十句,你能不能做处理?你没处理你的系统会不会挂掉?

第五是失效的功能级授权。对象级授权可以认为比如说是用户订单,这是用户功能级。比如说我的 get 、put 、post类似这样。我如果完全信任从前端过来的,我是不是可以创建一个 admin 的用户呢?实际上这也说明我们的后端不能完全信任前端的输入。如果你要信任也可以,比如说我要保证我的前端都不能动,那么我前端必须签名,确保中间是不能被篡改的。一旦有你签名,做了加密之后,就算后端他拿到之后,如果中间改了,是能够校验出来的,这个时候也能保证我有想要的,还有一个就是 get the users 。

怎么预防呢?强制执行机制应拒绝所有访问,要求显示授予特定角色才能访问每个功能。这个就是我们所说的最小权限原则,一开始不能有任何权限,只有他需要的时候,你才赋予权限。这是默认没有权限,而不是默认有。还有要考虑应用程序逻辑的时候要检查端点。

第六个是批量分配。我们可以看个例子,比如说我们有一个请求,它带有一个附加属性,这个附加属性很可能是你不经意的。但是如果你用 get 请求改了那个属性之后,它是可以重新被覆盖的。我可能发个 reques 过去,然后拦截了中间的 the respond , 回来的时候我把 respond 的结果改了,你前端给我响应的时候就变了。所以说后端返回的东西,我们前端也是要去校验它。我们前端对于后端的返回值也不是完全信任的,特别是一些非常敏感的一些属性。

怎么预防呢?第一,避免把用客户的输入自动绑定到代码变量以及内部的函数,这是防止注入。然后客户端的更新属性要列到白名单,然后还有内置的客户端不应该响应访问的列到黑名单。

第七就是安全配置错误。今天我看了有一个案例,它的 git 库里面类似有个点 git 的类似带点号的这些文件夹,大家要慎重,这些文件夹是不能上传到你的代码库的。类似 batched historical 可能含有一些敏感的数据。还有一个默认的配置,默认端口、默认的用户名和密码等,这些都是安全配置的问题。

怎么预防?第一,默认的东西应该是全都删掉或换一套。然后只允许该开放哪个端口就开放哪个端口,不要什么端口都开放。而且最好整个过程应该是自动化的,不要说发布在开发环境是一套,发布到生产环境又是另外一套,这个过程应该是可重复的、可自动化的、可验证的。

第八是注入。注入大家应该都是很清楚了,无非就是 SQL 注入、命令行注入,XSS 注入等。而且注入就是你太信任于前端的输入,你预期它是输入一个 ID 结果它输入的是一串命令。对于注入的预防,实际上我们一般说的就是输入要做校验,输出要做编码,然后输入校验一般用白名单,而不是用黑名单,黑名单还是很容易绕过的。

第九是资产管理不当。有可能一些老的版本,它可能有一些你不知道的风险,你要把它给管理起来。

最后一个就是日志和监控不足了。比较常见 的就是API 的密钥泄露。很多时候你在 git 上源代码泄露出去了,里面含有的密钥你可能都不知道。现在要依赖于一些监控的工具来及时发现了。怎么预防?对于所有的失败都应该记录起来到日志里面去,对于所有的你认为的异常都应该记录起来。

接下来是我对于 API 安全的一些思考。

首先我们看一个对比图,是我整理的OWASP API Top 10 2019以及现在的OWASP Top 10  2020 版本之间的对比。失效的对象级授权以及失效的功能级授权都可以归结于失效的访问控制,这已经在 OWASP 里面列到 A1 了,说明这个是非常引起关注的。然后失效的身份认证列到A7,然后过度的数据暴露、批量分配都可以列到不安全的设计。然后安全配置错误,也有对应项,注入也有对应项,资产管理以及日志的监控不足都可以列到A9。实际上我们可以看到很多的问题,很多的漏洞。实际上无论是 OWASP API Top 10 也好,还是OWASP Top 10 也好,都是一致的。

对于API安全的关注点是什么?

第一,授权是关键。大家都看到了无论是OWASP Top 10  2020以及 OWASP API Top 10 ,第一都是授权,认证不等于授权,功能 A 授权了不等于功能 B 授权,特别是组合对象之间的授权一定要关注。 

第二个,安全是设计出来的。我们要做威胁建模要最小化原则,不要怕麻烦,一定要是默认不许可的,是默认没有任何权限的,有需要才加。还有配置最容易犯错误。不要默认值一定要最小攻击面。什么叫最小攻击面呢?比如说你装完一个 token ,他可能带一些自己 default 的应用,那些东西都要删掉,不要留在你的生产环境,生产环境应该是越少越好。

还有注入是永恒的话题。我们怎么保证注入呢?输入要做校验,输出编码,白名单一定是比黑名单更安全的。还有,日志监控是必要的。我是这样认为,凡是错误必有日志,凡是日志一定是不能更改的。

 

所有文章
×

还剩一步!

确认邮件已发至你的邮箱。 请点击邮件中的确认链接,完成订阅。

好的