聊聊 API 安全的重要性及治理思路
在应用程序开发过程中,API 是一个会被经常提及的东西,它的全称是 Application Programming Interface(应用程序接口),一般指的是 Web API,即:采用 HTTP 通信协议的 API 或者是 Web 应用程序对外提供的 API。
API 从狭义上可以理解为是一种服务能力,调用方可以利用 API 很便捷的得到一组相关数据,但却不需要理解其内部的工作机制。
而在大型的软件系统中,API 还可以作为不同应用程序之间的一种契约,通过它可以将应用程序进行组装,从而实现业务逻辑更为复杂的功能。
所以,API 的设计将变得至关重要,合理规范化的设计,不但能够降低应用程序集成成本,提升软件系统开发效能,还能够增加 API 的可读性,有助于 API 的管理维护。
通常 API 设计思路会遵循如下几点
至今,在软件开发领域中,API 所能带来的价值已经显而易见,甚至它是驱动创新的基本要素,但要知道,世界上任何事物,都有两面性,API 也不例外。
在互联网的世界里,“安全”和“开放”是一个永恒的话题,但“开放创新”的前提必然是“安全可控”,也就是说没有安全的 API,创新是不可能的。
那些不安全的 API 势必将成为攻击者的主要目标,他们不但可以从中窃取高价值的数据,还能破坏应用程序的正常运作。由此可见,API 的设计中应当更加注重安全性。
什么是不安全的 API
先来介绍一下 OWASP 这个组织,全称是 Open Web Application Security Project,它是一个开源的全球性安全组织,致力于应用软件的安全研究。
它的使命是使应用软件更加安全,使企业和组织能够对应用安全风险做出更清晰的决策,同时推动安全标准、安全测试工具、安全指导手册等应用安全技术的发展。
在 OWASP 的众多项目中,可以发现有一个有关于 API 的安全项目,它不同于更广泛的 Web 应用程序安全项目,API 安全项目更专注于理解和减轻与 API 相关的独特漏洞和安全风险。
OWASP 在 2019 年颁布了 API 安全 TOP10 的第一版,其中列出了常见的 API 安全风险,如下是 API 安全 TOP10 的中文翻译概览。
它的主要读者对象可以是开发人员、架构师、管理人员、甚至是企业或组织,当你读完第一遍时,不知会有怎样的感觉,如果没有感觉,那就请你再读一遍。
TOP10 的安全风险排名采用了风险评级方法,分别从可利用性、弱点普遍性、弱点可检测性、技术影响 4 个方面进行评级,有兴趣的同学可以在 OWASP 官网,查阅到 API 安全 TOP10 中每一项评级结果及内容说明。
但请注意,这个风险评估方法,并不会考虑威胁来源的可能性以及实际的业务影响,它仅用于企业内部根据自身情况,来评估接受多少应用程序以及 API 引入的安全风险。
API 安全风险的治理思路
在充分了解 API 安全设计的重要性,以及 API 安全风险所带来的影响范围后,你必定会反问道,是否有快速增强 API 安全设计的捷径。
很显然,世界上就从来没有捷径,但 OWASP 提供了一套较为完整的治理思路,包括教育、安全要求、安全架构、标准的安全控件、软件安全开发生命周期五个方面,同时还配套提供大量免费的资源,来全面治理 API 安全风险。
看到这里估计你会意识到,API 安全风险治理将是一个复杂工程,如果你的企业中没有一些同时擅长应用和安全技术能力的人,恐怕这项工作将会很难推动,即便是有,其工作量和难度也非比寻常。
当面对复杂问题时,采用分而治之的办法,是一种比较高效的方法。换言之,可以考虑将 API 安全风险治理这个复杂问题,拆分为若干个子问题,然后再根据当下的资源及能力逐一攻克。
那么,就拿 API 安全 TOP10 来看,可以考虑优先选择某一条进行治理。它可以是企业内部评估安全风险较大的一条,或者也可以直接参考 API 安全 TOP10 的排名,比如:TOP10 的第一条,我想这可能是大部分企业最优先治理的一条。
另外,在 API 安全风险治理的探索过程中,还需要不断寻求规律及沉淀经验,以及求证治理方法的合理性及有效性,从而逐渐形成适用于企业自身的治理方法论,及 API 安全架构与设计规范。
不过,仅一份 API 安全架构与设计规范,并不能起到根治的效果,企业内部还得配套制定 API 安全管控流程,开发 API 安全风险识别工具才行,俗称:API 安全风险治理三板斧。
API 安全架构的设计思路
API 安全架构与设计规范,可以通过定期宣导和培训进行传播,但实际效果并不会特别乐观。主要的问题根源还是在于有些开发人员,较为缺乏 API 安全开发的意识。
他们甚至连花费 10 分钟的时间,来阅读 API 安全架构与设计规范都不乐意,何况是让他们能够主动去改善,而在庞大的应用架构中,还存在着成千上万个应用程序或 API,想要所有的开发人员,都能在安全意识上自驱更是难上加难。
那么,是否有一种 API 架构设计,能够尽可能减少对开发人员的依赖性,但又能起到部分 API 的安全访问能力。引入 API 网关可能是一个不错的选择,即:所有应用程序的 API 都将通过 API 网关对外进行暴露,特别是那些暴露至公网的 API。
为了便于读者快速理解,绘制了这张 API 架构示意图。总体结构从内到外共分为三个部分,分别是 API 资产池、API 网关、API 调用方。接下来就分别对它们进行简单介绍。
API 资产池
可以理解为相关性紧密的 API 集合,相关性可以根据业务领域、组织架构或其他等维度进行识别。而将 API 资产化纯粹是为了凸显它的价值性。
API 调用方
可以理解为 API 的服务对象,或者为调用 API 的用户或应用程序,服务对象基本可以分为合作机构、外部用户、内部用户、内部应用四种类型。
API 网关
可以理解为用于连接 API 资产池与 API 调用方的通道,它将作为 API 对外进行暴露的唯一入口,而面向不同的 API 调用方,可以设计不同场景的 API 网关。
综上,笔者将这种 API 架构称之为“护城河”架构,将 API 网关比喻为“护城河”,除 API 资产池内部互访及特殊场景下,其余 API 访问必须经过“护城河”,且大部分情况下“护城河”仅对持有通行证的用户或应用程序放行。
注:特殊场景可能为应用程序对内暴露的部分管理功能,例如:指标监控、健康检查等。
而不同场景的 API 网关对 API 调用方的安全要求等级也会不同,通常对外网的安全要求会比内网要高。最终可以形成如下这张 API 资产访问清单。
通过这种 API 架构设计,可以将安全访问控制能力,从应用程序中剥离至 API 网关,一方面可以让应用程序更专注于实现业务服务能力,另一方面可以对 API 访问入口进行集中收口,规避因开发人员安全意识不足而注入的访问控制安全问题。
API 安全治理的实践思路
用过 API 网关的同学都知道,它的核心能力主要是流量路由转发及分流。所以,缺省情况下,它并不会启用安全控制能力,因此,你需要根据实际使用场景,选择开启不同的安全控制能力。
API 网关一般都支持如下安全控制能力
前文有提到过,不同场景的 API 网关对 API 调用方的安全要求也会不同。所以,并不是说所有 API 网关都要实现或开启以上控制能力,根据实践使用经验,参考如下
注:*代表在移动端环境下为必须。
可以发现,面向公网的 API 安全控制要求要远远高于内网。所以说,在 API 安全治理的优先级上,建议采取先外后内的实践策略,毕竟面向公网的 API 处在一个完全开放的环境下,它更容易受到致命性的攻击。
另外,在最新的 2021 年最新版的 OWASP TOP10 中可以发现,“失效的访问控制”已从第五位上升到第一位,而如下这组风险因素数据,更能说明访问控制的安全风险,它将会越来越受到攻击者的“青睐”。
在明确 API 安全治理的实践策略后,就需要制定相应的实践步骤,而对于治理类相关的工作而言,一般主要有三个步骤:定义目标+识别差距+治理问题。
在完成第一轮治理后,重新定义目标并进行新的一轮,通过这种持续不断地加速循环,达到最终的 API 安全治理目的。
第一步:定义目标
在启动 API 安全治理前,最重要的任务,就是定义目标并明确范围,从而牵引工作始终朝着正确的方向推进。
API 安全治理所涉及的范围非常大,所以初期可以考虑缩小治理范围,并确定一个可达的目标。例如:可以将公网 API 访问控制治理作为第一个目标。
在公网 API 访问控制方面,暂且列举了可能存在问题的两种主要现象,其中第一种,应该很容易理解,但是第二种,会觉得有点奇怪,这里谈论的是公网 API 访问控制,与内部 API 有什么关系。
但令人恐怖的是,有些开发人员在不知情的情况下,误将内部 API 直接暴露到公网上,而内部 API 安全控制可能相对较弱,甚至没有任何安全控制。
请试想一下,如果一个活动秒杀类商品库存可以被外部攻击者任意修改,将是一种怎么样的体验,我想可能不是秒杀商品,而是秒杀企业。
所以,不管是外部 API 还是内部 API 都将会在这个治理范围内,只不过治理目标有所区别,对于外部 API 需要增加安全控制手段,而对于内部 API 需要杜绝暴露至公网。
第二步:识别差距
在定义目标并明确范围后,可能还不能真正启动治理工作,还需要识别当前 API 现状与治理目标之间的差距,这样才能明确治理的方式和手段,而在识别差距前,还得收集当前 API 清单及现状。
如果你的企业中,API 有专门的管理平台进行管理维护,那么收集 API 清单可能相对容易,但有些企业可能还在使用电子文档管理 API,那么这项工作将会变得十分困难。
所以,这时可以考虑开发一个 API 扫描工具,自动获取应用程序中对外暴露的 API,对于主流的 Java 应用程序而言,你的第一反应可能会想到,可以在源代码中,通过检测 @Restcontroller 或 @Controller 注解来识别 API。
这种方式确实可以扫描到部分 API,但可能并不完整,一是对外暴露的 API 不一定都采用注解的方式,二是应用程序引用的第三方的包中,也对外暴露了 API,这部分可能是扫描不到的。所以,需要换一种方式,来获取应用程序对外暴露的全量 API。
如果你的 Java 应用采用了 Spring 框架,那么可以考虑采用如下这个方法,在应用程序启动初始化后,可以从 handlerMappings 获取所有对外暴露的 API 信息。
org.springframework.web.servlet.DispatcherServlet 的代码片段如下
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
// We keep HandlerMappings in sorted order. AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
但要声明的是,API 扫描工具并不是万能的,它仅仅只是提供了另一种手段,帮助你解决 80%以上的问题,对于还在使用电子文档管理 API 的开发人员,还是建议对扫描后的结果进行查漏补缺。
另外,除了 API 扫描工具外,还可以抓取网络代理组件中的访问日志进行识别,最终结合扫描工具、自查上报、访问日志三部分的信息,形成一份较为完整的 API 清单,虽然它可能并不是完整的,但在条件有限的情况下,这可能是最好的结果。
有了 API 清单后,接下来需要对它们分门别类及现状分析,如下简单设计了 API 分类字段,你可以根据自身需要再进行调整或补充。
根据第一步定义的目标,可以先将所有允许公网访问的 API 全部筛选出来,随后分别对这些 API 进行现状分析及识别差距,例举如下:
方法请求配置原则上仅允许 GET/POST;
跨域请求配置原则上默认不允许,需单独申请批准;
API 服务对象原则上不允许为内部应用;
API 服务对象若为合作机构,安全要求如下;
注:*代表 API 是 A2 类时为必须。A1/A2 分类可参考《商业银行应用程序接口安全管理规范》
API 服务对象若为外部用户/内部用户,安全要求如下;
注:*代表在移动端环境下为必须。
最后,根据针对每一条 API 所识别出来安全问题进行等级评定,前期为了简化工作难度,在没有安全风险量化指标之前,建议直接根据安全技术人员的经验,标记为高、中、低即可。
第三步:治理问题
当识别出所有 API 安全问题后,就可以全面启动治理工作,可以分别从 API 架构设计治理、API 安全访问治理、API 管控流程治理三个方面共同启动。
在 API 架构设计治理方面,将对 API 的暴露方式进行调整,暴露至公网的 API 将全部通过 API 网关进行暴露,并在 API 网关上配置 API 路由访问策略。
对于存在安全问题的 API 建议根据等级评定来决定是否立刻整改,剩余其他 API 建议逐步进行迁移,而对于以后新开发的 API 要求直接采用这种模式。
在 API 安全访问治理方面,将 API 安全控制能力从应用程序中剥离至 API 网关进行承接,所有应用程序都将由 API 网关进行安全保护。
当然,应用程序可在有条件的情况下,保留部分安全控制能力,只要不与 API 网关存在安全控制冲突即可。
在 API 管控流程治理方面,还需要分别在 API 发布的事前、事中、事后三个阶段增加必要的控制手段。
事前:API 暴露公网提交申请,并在审核通过和必要的渗透测试后才会在 API 网关上进行注册并对外暴露,从而避免内部 API 误暴露至公网的情况发生;
事中:API 请求增强异常监控,对于发现大量鉴权/验签失败、触发限流/防重等现象后进行预警,并由人工介入排查是否存在安全风险并及时进行拦截;
事后:API 请求访问日志分析,对访问日志进行安全风险分析,包括撞库异常行为、数据过度暴露、敏感信息泄漏、上下文行为异常等访问安全数据分析;
因篇幅有限,以上三个步骤仅是围绕公网 API 访问控制治理进行了简要的实践说明,但这仅仅只是 API 安全治理的一小部分。
另外,API 网关也并不能解决你所有的 API 安全问题,更多的还是应用程序自身需要进行 API 安全治理,例如:失效的功能级授权,即:水平越权安全漏洞。
写在最后
本文依次从突出 API 安全的重要性,到列举什么是不安全的 API,及全面治理的思路方法,再到如何通过 API 架构设计减轻 API 安全问题,以及最后针对某 API 安全问题的实践过程分别进行了一一阐述。
它可能并不全面,或者说并不完全适用于所有情况,但本文的意义,更多的是为了起到抛砖引玉的效果,启发对 API 安全开发的思考,唤醒对 API 安全开发的意识。
在最后的最后,想说的是,赶在节前输出一篇有关于安全的文章,寓意并祝愿大家安安全全过大年,疫情过后尽开颜。
文章中部分截图来自于 OWASP 官网/中国网,并基于《Creative Commons Attribution Share-Alike 4.0 license》进行发布。
期待追求技术的你,可以一起探讨交流。
版权声明: 本文为 InfoQ 作者【陈俊】的原创文章。
原文链接:【http://xie.infoq.cn/article/64582036401a6fb457f450e5f】。文章转载请联系作者。
评论