【51CTO.com快译】如今,无论是以API为主营服务(API-first)的公司,或是单页面应用/JAMStack,都通过各种丰富的API对外公布着大量的数据。不过,由于这些数据能够被直接地访问到,而且绕过了浏览器的预防机制。因此,我们需要担心的不再是SQL注入和XSS等“入向”问题,而是敏感数据记录可能被窃取等API“出向”安全性问题。此外,由于API被设计为能够向单个客户端提供大量的API访问,因此诸如验证码(Captchas)和浏览器指纹识别之类的典型预防机制,也不再能够起到明显的效果。
那么,我们该如何开始做好API的安全防护呢?在此,让自己从攻击者的角度来检查目标API,以阻断常见的未知对象攻击,并参照OWASP安全API列表
(请参见--https://owasp.org/www-project-api-security/),来防范各种零日漏洞的利用。
1. 限制不安全的资源访问
大多数API都提供了对于实体列表(例如/users或/widgets)的资源访问。诸如浏览器之类的客户端通常会使用如下方式,来进行过滤和分页(pagination),以限制返回给客户端的条目数:
First Call: GET /items?skip=0&take=10 Second Call: GET /items?skip=10&take=10
但是,如果该实体中含有任何PII(个人身份信息)或其他敏感信息,那么攻击者就可能通过该端点,获取数据库中的所有实体信息。一旦这些实体的PII被意外泄露,竞争对手就能够推断出贵企业的采购信息和客户状况,甚至是大量的邮件列表。如果您对此有兴趣的话,可以参看《如何清除Venmo数据》
(https://22-8miles.com/public-by-default/)一文。
常规的保护机制是记录那些大于100或1000条的条目,并抛出异常信息。下面是两种常见的默认保护方法:
对于数据型API,合法客户可能需要获取并同步大量的记录,并通过各种cron作业来实现。那么人为地限制分页的大小,会迫使API频繁地进行同一种操作,进而降低了整体吞吐量。可以说,此类最大条目限制方法主要是为了满足内存和可扩展性的要求,以及防止某些DDoS攻击。
如下代码段所示,通过编写简单的脚本,在重复的访问之间,随机休眠一段时间。当然,此类防护对于攻击者来说,并非总是奏效。
skip = 0 while True: response = requests.post('https://api.acmeinc.com/widgets?take=10&skip=' + skip), headers={'Authorization': 'Bearer' + ' ' + sys.argv[1]}) print("Fetched 10 items") sleep(randint(100,1000)) skip += 10
2. 防止分页攻击
为了防止分页攻击,您应该跟踪在一定时间段内,用户或API密钥访问某个资源的数量,而不是仅仅停留在请求本身。您可以在用户或API密钥达到阈值时(例如:每个用户或API密钥在一个小时内之允许调用1,000,000条记录)阻止它们。当然,具体阈值的设定取决于您的API用例,以及它们的订阅方式。就像每分钟只能发送一次验证码那样,此举减缓了黑客调用目标API的速度。对此,攻击者不得不手动创建更多新的帐户或API密钥。
3. 保护API密钥池
大多数API会受密钥或JWT(JSON Web令牌)的保护。由于API安全工具可以检测到异常的API行为,并自动阻止对于API密钥的访问,因此这是跟踪和保护API的原生方式。但是,攻击者往往会使用大量的IP地址,来规避DDoS的检查;并通过生成大量的账户,来获取大量的API密钥。
抵御此类攻击的最简单方法是要求用户注册自己的服务,并生成对应的API密钥。我们可以通过使用验证码和双因素身份验证,来阻止各种僵尸(Bot)流量。除非是合法的业务用例,否则新注册服务的用户不能够以程序的方式,生成API密钥。相反,只有那些受信任的用户,才具有生成API密钥的能力。据此,我们可以确保在帐户级别(不仅仅针对每个API密钥)上,对异常行为进行异常检测。
4. 防止意外的密钥泄露
总的说来,如下使用API的方式会增加密钥泄漏的可能性:
如果您将该API密钥保存在服务器的环境变量中,并提供侍候型的访问方式,那么就会增加黑客获得有效且未过期的密钥的可能性。这显然不及用户在登录交互式网站时,在会话中使用较短时间到期的API密钥安全。
API的使用者可以直接访问到密钥,例如通过Postman或CURL进行调试。那么任何一个开发人员都可以将含有API密钥的CURL命令,意外地复制/粘贴到诸如GitHub Issues或Stack Overflow之类的公共论坛中。
如果不采用一次性令牌或双因素身份验证,API将无法保护其密钥。
防止密钥泄露的最简单方法是利用两个令牌而非一个。刷新令牌(refresh token)被存储为环境变量,并且只能用于产生短暂的访问令牌(short lived access tokens)。与刷新令牌不同,这些短暂的令牌可以访问到资源,但是有着时间的限制,例如数小时或数天。
客户存储刷新令牌和其他API密钥。SDK会在其初始化时、或是最后一个访问令牌到期时,生成新的访问令牌。如果CURL命令被粘贴到GitHub中,那么攻击者必须在数小时内使用短暂的访问令牌,不然就会过期(毕竟他获取到刷新令牌的可能性极低)。
5. 阻止DDoS攻击
API开辟了全新的业务模式,用户可以在其中以编程的方式访问到目标API平台。但是,这也会使得针对DDoS保护变得十分棘手。大多数DDoS的保护机制是清洗或拒绝攻击者发来的大量请求。但是为了让混淆在僵尸流量中正常请求能够顺利通过,我们需要对HTTP请求进行指纹识别。但是对于API服务而言,这是极其困难的,毕竟所有的流量都看上去像僵尸流量,而非来自浏览器的Cookie。
如今,绝大多数的关于API的访问和调用都需要用到API密钥。如果某个请求中没有API密钥,则会被自动拒绝。那么,我们该如何处置那些经过验证的请求呢?目前,最简单的方法是利用每个API密钥的速率限制计数器,例如:我们可以预先设定每分钟可以处置X个请求,那么对于超过这个数量级的请求,则以带有HTTP 429的响应方式予以拒绝。目前,我们可以采用诸如漏斗和固定窗口计数器等多种算法,来实现这一点。
6. 通过正确的SSL来确保服务器安全
其实在服务器安全方面,API与Web服务器并无太大差别。错误配置的SSL证书,或默认允许非HTTPS的流量通过,都可能导致数据的泄漏。如今,非HTTPS请求虽然已经逐渐被HTTPS所取代,但是用户仍然可能错误地从其应用程序、或泄露了API密钥的CURL中发出非HTTPS的请求。而且API是无法实现HSTS(HTTP Strict Transport Security,HTTP严格传输安全协议)、或HTTPS重定向之类的浏览器级保护的。
目前比较普遍的做法是通过Qualys SSL Test(请参见--https://www.ssllabs.com/ssltest/)或类似的工具,来实施并测试SSL。无论您的API是仅供自己的应用来访问,还是要在服务器端被访问到,您都可以通过负载均衡设备来阻断所有非HTTPS头的请求。具体请参见《REST API跨域资源共享权威指南》
(https://www.moesif.com/blog/technical/cors/Authoritative-Guide-to-CORS-Cross-Origin-Resource-Sharing-for-REST-APIs/?utm_source=dzone&utm_medium=blog&utm_campaign=placed-article&utm_term=top-10-api-security-threats)一文。
7. 确保正确地配置缓存头
API通过不同的密钥,提供了对于既定范围内动态数据的访问。那么任何缓存机制的实现,都应该基于API密钥的范围,以防止出现数据的“交叉污染”。例如:某个用户通过代理服务器正在使用多个API密钥,其中一个被用于开发环境,另一个被用于生产环境,那么两个环境中的数据就可能产生相互泄露。此方面的一个真实案例是:Twitter曾在数据安全事件后证实泄漏了账号相关信息(请参见:
https://www.bleepingcomputer.com/news/security/twitter-discloses-billing-info-leak-after-data-security-incident/)。
通常情况下,许多API并不使用标准的认证头,而是类似于X-Api-Key的自定义头。如下代码段所示,缓存服务器在并不知晓此类请求是否已通过验证的情况下,只能选择对其进行缓存。可见,我们应该正确地配置缓存控制(Cache-Control)头。
app.use((req, res, next) => { res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate'); res.setHeader('Pragma', 'no-cache'); // ... });
8. 正确地添加API日志记录
通过对大多数入侵案例的研究,OWASP层发现:企业通常需要超过200天,才能检测到数据发生了泄漏事件。而且,如果未能采用适当的API日志记录和监控,攻击者可能会持续使用相同的漏洞,进而探测到更多的漏洞。
我们不但应该确保API日志记录能够跟踪API的请求本身,而且需要通过绑定以实现对用户行为的分析。与此同时,此类系统应当受到相应的保护,以确保数据记录不会被意外地删除,或过早地销毁掉(应至少存储一年)。为了安全起见,GDPR和CCPA都允许系统开展API审计。如下图的API审计日志所示,像Moesif API Security
(https://www.moesif.com/solutions/api-security?utm_source=dzone&utm_medium=blog&utm_campaign=placed-article&utm_term=top-10-api-security-threats)之类的方案,能够为API产品提供了一整套监视和分析功能,并且用户只需数分钟就能够快速上手。
9. 正确地处理授权
虽然大多数API开发人员都会自觉地添加诸如API密钥、或OAuth之类的全局性认证方案、来验证调用方的身份。但是,我们也需要通过授权的方式,来检查他们是否可以访问某些特定的资源。对此,我们往往会借用访问控制列表(ACL),并为相关对象分配不同的角色,来实现基于角色的访问控制。您可以参考《为RESTful API构建身份验证和授权的步骤》一文(请参见--https://www.moesif.com/blog/technical/restful-apis/Authorization-on-RESTful-APIs/?utm_source=dzone&utm_medium=blog&utm_campaign=placed-article&utm_term=top-10-api-security-threats),以了解具体的防护方法。
10. 保护内、外部端点
同一项API服务有可能具有内、外不同的使用端点。那么,除了使用身份验证和授权等基本保护方案之外,我们还应通过启用负载均衡器或API网关,以确保这些端点不会完全暴露于公共互联网上。此外,我们也可以通过提供多级安全性(一种常见的预防策略),来进行API的防护与加持。
原标题:Top 10 API Security Threats Every API Team Should Know ,作者:Derric Gilling