如果您一直关注物联网的发展,您会注意到围绕新兴行业安全要求的大量讨论。事实上,这是我们在自己的博客中多次提到的主题, 感到脆弱:物联网安全 、 互联城市,第 1 部分:建设未来的互联城市 和 物联网连接:第一次就做好 。在这篇博文中,我们希望开始更深入地研究安全性,并了解您可以采取的一些措施来保护您的数据。
安全性可能是编程的一个令人生畏的领域——特别是如果您没有在该领域广泛工作的话。考虑到这一点,我们将从您可以采用的一些更常见的安全措施开始。具体来说,我们将研究 SSL/TLS——一个我们至少都比较熟悉的安全领域。
SSL/TLS 最常见的应用是作为网络浏览中使用的加密层。 HTTPS 允许在知道您的数据安全的情况下安全地执行网上银行和类似的敏感应用程序——除了一些引人注目的安全漏洞(Heartbleed、POODLE、Apple 的 goto fail;),我们将在更多稍后在帖子中详细介绍。
SSL 或 TLS
SSL 或安全套接字层是 TLS 或传输层安全性的前身。 SSL 有三个版本,由于设计缺陷,它们都被认为是不安全的。 TLS 的创建是为了解决 SSL 协议中的弱点。术语 SSL、TLS 和 SSL/TLS 在文献中通常可以互换使用。
值得注意的是,尽管 SSL 存在固有的弱点,但它至今仍在使用。服务器 SSL/TLS 堆栈中对 SSL v2.0/3.0 的支持旨在实现向后兼容性。当然,这种支持是 POODLE 攻击的目标。在 POODLE 中,连接被降级到 SSL v3.0,然后允许入侵者攻击 SSL v3.0 常用的 CBC(密码块链接)模式加密方法。 POODLE 攻击的解决方案是让服务器端管理员禁用降级功能,并将其连接保持在更安全的 TLS 上。
如果您正在开发应用程序,您可能会控制服务器端。如果是这种情况,您希望使用 TLS 连接。
SSL/TLS 是如何工作的?
设置 SSL/TLS 会话包括三个主要步骤——非常粗略地说,如果我们要详细说明,这可能是一篇很长的文章。第一步是就密码套件达成一致——密钥交换算法、密码和消息认证代码的组合。密码套件在 SSL/TLS 握手的客户端/服务器问候交换中达成一致。第二步是按照约定的密钥交换算法交换密钥。最后,第三步是使用协商的密码和交换的密钥建立加密连接。
非对称(公钥-私钥)加密最初用于允许密钥交换。然后使用对称密钥加密(使用密钥交换步骤生成的密钥)来加密您的应用程序数据。
密钥交换算法和用于加密的密码都有很多选择——快速浏览一下密码套件的 IANA 注册表 会让您相信这一点。必须及时了解新出现的安全问题,以便告知您首选密码套件的选择。 OpenSSL(我们将在帖子的下一节重点介绍的 SSL/TLS 实现)在其 新闻页面 上发布有关 OpenSSL 的安全建议。 ThreatPost 和 CNET Security 是其他很好的安全信息来源。
打开SSL
OpenSSL 是 SSL/TLS 功能的开源实现,应用非常广泛。如果您要自己加密套接字——而不是使用启用 SSL/TLS 的 Web 服务器(如 Apache)——OpenSSL 是一个很好的起点。当然,Apache 本身使用 OpenSSL,但所有低级 OpenSSL 调用都将内置到 Apache Web 服务器中。
要使用 SSL/TLS 包,您首先必须打开要加密的连接。这将以正常方式完成,在客户端进行连接(可能需要手动绑定),在服务器端进行绑定、侦听和接受。建立连接后,您可以开始添加 SSL/TLS 加密层。
您首先需要初始化 OpenSSL 库并加载错误字符串——这非常有用,尤其是在开发阶段——使用以下调用。
SSL_library_init();
SSL_load_error_strings();
接下来,您需要创建一个 SSL_METHOD、一个 SSL_CTX 结构、一个 SSL 结构并将 BIO 添加到 SSL 结构。 SSL_METHOD 结构描述了您的连接支持的 SSL/TLS 版本。 SSL 结构用于建立、读取、写入和断开加密连接。 SSL_CTX 结构包含与所有 SSL 连接相关的信息。 BIO 是 OpenSSL 库中使用的 I/O 抽象; BIO 允许将 SSL/TLS 加密应用于许多不同的数据交换——而不仅仅是我们关注的 TCP/IP 交换。可以使用以下调用创建和(最低限度)配置这四个结构。
SSL_library_init();
SSL_load_error_strings();
其中sock指的是已经建立的未加密套接字。如果您在服务器端编程,您还需要使用调用加载私钥和证书文件——当然是在您初始化 SSL_CTX *ctx 结构之后。
SSL_library_init();
SSL_load_error_strings();
完成此设置后,您可以通过调用创建加密连接
SSL_library_init();
SSL_load_error_strings();
在客户端和
SSL_library_init();
SSL_load_error_strings();
在服务器端。如果您使用的是阻塞套接字,这些调用应该完成并且您的加密连接应该很容易建立。如果您使用的是非阻塞套接字,您应该检查每个调用的返回值,因为当底层套接字可用于读/写时您可能需要再次调用这些函数——请参阅这两个调用的手册页以获取更多详细信息。
建立加密连接后,您可以使用调用读取或写入加密套接字
SSL_library_init();
SSL_load_error_strings();
就是这样。您现在拥有一个可以读取/写入数据的加密连接。
您的加密开发
关于加密您自己的套接字的最后几点注意事项。
首先,如果您在开发期间尝试调试您的代码,那么能够查看套接字上的交换是很好的——看看出了什么问题。 Tcpdump 和 Wireshark 是完成此任务的出色工具。 Wireshark 甚至可以让您加载您的服务器私钥文件,以便您可以看到未加密的数据交换——当然假设您选择的密码套件没有前向保密。
其次(更重要的是),上面显示的 OpenSSL 代码片段描述了 OpenSSL 套接字的基本实现。作为开发人员,您可以使用更多选项。例如,您可以选择不同的 SSL_METHOD 来使用,或者您可以限制可用密码套件的列表以确保使用某些套件。这些选项必须作为明智的决定做出,因此不要将您的信息仅限于这篇短文。 OpenSSL Cookbook 是 Feisty Duck 的免费书籍,是开始学习更多知识的好地方。
最后,当您准备好部署加密时,下一步就是让受信任的证书颁发机构 (CA) 签署您的服务器证书。通过让受信任的 CA 签署您的证书,客户端将能够在连接设置过程中对您的服务器进行身份验证。将此步骤添加到您的客户端代码中非常重要。如果不这样做,您的平台就会受到中间人攻击。苹果走向失败; bug 是无法通过证书 CA 进行身份验证的一个引人注目的示例。
祝您编码愉快,敬请期待下周本安全系列的第 2 部分!