iOS上的证书固定技术

嗨伙计! 今天,我们将讨论安全性。 为了完全理解此处介绍的这些概念,我需要提供一些有关SSL / TLS如何工作的背景知识以及其他内容。 当然,这不是一个深入的探讨,它只是在开始主要主题之前的简单说明,如果您已经知道,没关系,只需退出本部分并转到下一部分。 在最后,我们将看到一个如何在iOS项目上进行证书固定的实际示例,让我们开始吧!

它是什么?

SSL / TLS确保通过HTTPS(即,基于SSL / TLS的HTTP)对客户端-服务器通信进行透明加密。 加密基于公共密钥基础结构(简称PKI)。 这是透明的,因为应用程序层对此加密过程一无所知,网络基础结构会处理一切,因为程序员我们只是编写应用程序请求,因此将带有纯文本的标头和正文放在请购单中,而网络基础结构则可以完成所有工作我们。

握手

在发送任何应用程序数据之前,服务器和客户端就如何加密/解密数据进行协商,此过程称为握手,在下图中,您可以看到有关此过程的简化视图:

握手后

此时,如果有人尝试检查在数据传输中客户端和服务器之间交换的消息,那么任何内容都不会被人类读取,所有流量在传输过程中都会被加密,即,仅从客户端和服务器的角度来解密。

证书验证过程

在握手过程中,服务器将提供数字证书,并且客户端需要基于预定义的信任证书颁发机构列表(也称为受信任的根CA存储)信任证书颁发者。 在安全连接上,如果所提供的证书是由未知的颁发者颁发的,则通常浏览器会显示警告⚠️,供用户决定是否必须继续进行连接。 默认情况下,在连接中断的情况下,应用程序上的此行为是不同的。 您有可能在设备上将自签名证书设置为受信任,在这种情况下,客户端将在后续连接中信任此证书。

中间人袭击

如果您的连接不是通过连接到原始服务器,而是通过另一台伪装成原始服务器的服务器,将会发生什么情况? 从Imperva Incapsula网站上看到有关中间人攻击的简要描述。

中间人(MITM)攻击是一个通用术语,指的是犯罪者将自己置于用户与应用程序之间的对话中-进行窃听或假冒其中一方,使其看起来像是正常的信息交换进展中。

在这种情况下,攻击者可以看到所有流量,并且可以捕获所有信息。

它是什么?

通过以上介绍的背景,我们可以更好地了解什么是证书固定。 众所周知,在握手过程中,服务器将出示必须由客户端信任或不信任的证书。 证书固定技术在于将目标的服务器证书保存在应用程序捆绑包中,并且仅对此信任。

我们的例子

让我们看一个实际的源代码,为此,我创建了一个在Heroku和一个客户端iOS项目上发布的存根身份验证剩余服务。

在发布本文档时,生成的证书尚未过期并且服务已启动。 当然,随着时间的推移,我无法保证,但是如果您正确地理解了这一概念,则可以更改证书和主机名以成功获得自己的服务。

在我们的示例中,我们将使用post方法访问以下URL https://floating-stream-25740.herokuapp.com/authentication/login来提交如下所示的请求:

POST /身份验证/登录HTTP / 1.1
主持人:floating-stream-25740.herokuapp.com
内容类型:application / x-www-form-urlencoded
缓存控制:无缓存

id = user&password = pass

通知的ID或密码无关紧要,它仅用于测试。 输出始终为:

{
“ Id”:“用户”,
“名称”:“ Sergio Mallandro”,
“首选项”:[“ XPTO”,“ XPTA”,“ XPTZ”]
}

必备工具

出于测试目的,我们将需要一些Web调试器来充当代理来模拟中间攻击中的人。 对于像我们这样的Mac用户,我建议两个选项,Charles Web Debugging代理应用程序或Burp。 两者都是商业解决方案,但是您可以获取试用版或免费版。 如果您在另一台计算机上运行Windows,则可以获得Fiddler,它是一个很好的免费选项。

客户样本项目

我们的客户端应用程序已发布在GitHub上:

heuristisk / hk es

hkPraesidium –这是一个SSL固定演示项目

github.com

事情发生的地方

该项目非常简单,它只是一个视图控制器类,它调用另一个API类来发出请求,以便将其结果放在TextView控件上。 为简化起见,我在这里将代码的一部分固定在逻辑上,基本上,我们有一个URLSession来执行请求,而API类实现了URLSessionDelegate来处理urlSession方法。 在urlSession方法内部,我们具有将远程证书与本地证书进行比较的逻辑,如果代码之间存在差异,则请求操作将被取消。

现在,如果您打开iOS模拟器并尝试通过safari在任何站点上进行连接,或者如果您运行此处显示的示例项目,您将看到请求和响应,如下图所示:

如果是安全连接,则无法读取任何内容,因为SSL / TLS保护。

现在尝试启用SSL代理:

糟糕! 连接失败! 为什么? Charles提供了一个自签名证书而不是原始证书,在这种情况下,当Charles应用程序收到连接请求时,它将尝试从客户端的角度充当原始服务器,并向原始服务器提出新请求。 当原始服务器答复该响应时,它会像原始请求一样被答复给客户端,但是Charles出示的此证书是不可信任的,我们需要使客户端信任它,以在中间攻击中模拟我们的人。
可以如下图所示进行:

之后,您需要对此证书启用完全信任,如果需要在真实设备上对其进行测试,则可以导出并手动安装。 之后,您需要重置模拟器。

现在,如果您尝试连接,您将在Charles上看到所有内容,就好像这是一个简单的HTTP连接一样:

但是,如果启用证书固定,我们的逻辑将比较嵌入式证书和显示的Charles证书,因此连接将被取消,如下图所示:

这种方法的优点是限制了客户端应用程序信任的签名授权机构的数量,CA在签名密钥被破坏或颁发的证书过于宽松的情况下,存在多个突出的安全漏洞。 这些漏洞使拥有签名密钥的任何人都可以模拟任何SSL / TLS服务器,这意味着他们可以成功,透明地读取或修改对服务器及其响应的请求。 另一个优点是您的应用程序不会通过代理应用程序(例如Charles)公开API合同。 不利的是,当服务器证书更改时,您的应用程序将停止工作,在这种情况下,您需要更新您的应用程序。

我希望它可以帮助您了解证书固定技术,如果不清楚,请在此处评论,也许我可以为您提供帮助并改进本文。 再见,再见! 👋