安全哈希算法支持

https://blueprints.launchpad.net/glance/+spec/multihash

本规范提供了一种面向未来的机制,为每个镜像提供安全的 SHA512 哈希值。

问题描述

可以从镜像元数据中的 checksum 字段获取镜像的哈希值。目前,此 checksum 字段包含一个 md5 十六进制摘要值。虽然 md5 仍然可以用于验证针对意外损坏的数据完整性,但它不应用于验证针对篡改的数据完整性。应使用更具抗碰撞性的哈希算法来提供更广泛的数据完整性覆盖。

提议的变更

本规范建议向镜像元数据添加两个新字段。此更改的建议键是 os_hash_algoos_hash_value。建议的值是格式为 sha512 十六进制摘要的哈希值。十六进制摘要将使用当前的 python hashlib 库获得。 os_hash_algo 将为 sha3_512,os_hash_value 将为十六进制值。目前,配置将默认设置为 sha3_512,但此更改将允许我们随时更改允许的哈希算法。 os_hash_algo 字段还将允许用户将其值动态传递到他们的 python 代码。我们将保留 MD5 计算和 checksum 以实现向后兼容性。

添加新镜像将设置所有 checksumos_hash_algoos_hash_value 字段。

请求缺少 os_hash_algo/os_hash_value 值的镜像元数据,将导致元数据响应中 os_hash_algo/os_hash_value 字段为空。

备选方案

  1. 更新 checksum 字段的值,以使用不同哈希算法的十六进制摘要。这将可能破坏客户端 checksum 验证代码。

  2. 仅添加新的 os_hash_value 字段。虽然这是一个更简单的更改,但它是一种不太面向未来的方法,因为它以与 md5 算法绑定到当前 checksum 属性相同的方式将 sha512 算法绑定到 os_hash_value 属性。当生成 sha512 碰撞时,将需要一个新的规范来添加另一个 checksum 字段。

    本规范中描述的方法,即使用额外的 os_hash_algo 字段,将允许更改哈希算法而无需添加新字段或破坏 API 合同。我们所要做的就是更新使用的算法并将其名称放入 os_hash_algo 属性中,然后任何镜像使用者都知道如何解释 os_hash_value 属性中的内容。

    值得注意的是,Glance 实现的镜像签名验证为我们提供了一个拥有一个属性 (img_signature) 中的值和另一个属性 (img_signature_hash_method) 中算法名称的先例 [1]。因此,本规范中的建议与相关的 Glance 工作流程完全一致。

  3. 使用不同算法的十六进制摘要。使用 hashlib 的 sha256 和 sha512 算法进行的测试始终产生 sha512 更快的时间 (参见:性能影响)。 hashlib 中 sha512 算法的实现表现出合理的性能,并且应被认为在多年内具有抗碰撞性。

  4. 在镜像元数据中实现单个 multihash 字段,其中我们将计算 SHA512 值。单个字段将包含编码的算法名称和哈希值 [0]。优点是只有一个字段被添加到数据模型和模式中。但是,只有一个字段会使快速使用哈希变得困难,因为最终用户需要解码使用的算法才能验证哈希。

数据模型影响

  • 触发器:无

  • 扩展:将向 images 表添加两个新列 (os_hash_algo & os_hash_value),类型为 string/varchar (默认值为 null)。我们将创建类似于 checksum 上的索引。

  • 迁移:无

  • 合同:无

  • 冲突:无

REST API 影响

在请求镜像元数据中将存在两个新字段 (os_hash_algo & os_hash_value)。

安全影响

将返回一个新的更具抗碰撞性的哈希值,以及当前的 checksum。

通知影响

其他最终用户影响

性能影响

新的镜像上传 (以及先前上传的镜像的首次下载) 将需要额外的计算时间来计算 sha512 checksum

5G 随机数据二进制 blob:* md5:~9s * sha256:~22s * sha512:~14s * 1Gbps 线路速度上传:42s

1.5G Ubuntu 16.04 云镜像:* md5:~2.9s * sha256:~7.2s * sha512:~4.6s * 1Gbps 线路速度上传:12s

555M Debian 8 云镜像:* md5:~1.0 * sha256:~2.5 * sha512:~1.6 * 1Gbps 线路速度上传:4.5s

  • 注意:已选择 SHA512,并且在考虑到整个过程的情况下,它应该对整体上传时间产生最小的影响。

测试代码

#!/usr/bin/env python3

import hashlib
import time


def runtime(f):
    def wrapper(*args, **kwargs):
        start = time.time()
        f(*args, **kwargs)
        print("Time elapsed: %s" % (time.time() - start))
    return wrapper


@runtime
def checksum(filename, algorithm):
    algorithms = {"md5": hashlib.md5,
                  "256": hashlib.sha256,
                  "512": hashlib.sha512,
                  }
    with open(filename, "rb") as f:
        m = algorithms[algorithm]()
        for chunk in iter(lambda: f.read(65536), ''):
            m.update(chunk)
    print("%s: %s" % (algorithm, m.hexdigest()))

checksum("fake.img", "512")
checksum("fake.img", "256")
checksum("fake.img", "md5")
checksum("fake.img", "256")
checksum("fake.img", "md5")
checksum("fake.img", "512")

开发人员影响

任何未来的 checksum 验证代码都应使用 os_hash_algo & os_hash_value 字段。如果未正确填充,则回退到 checksum 字段。

实现

负责人

主要负责人:Scott McClymont

其他贡献者

工作项

  • 添加测试

  • 更新数据库以向 images 表添加 os_hash_algo & os_hash_value 列 (包括扩展、迁移、合同和单体代码)

  • 更新计算 checksum 的代码部分,以同时计算 os_hash_algo & os_hash_value (包括上传时的计算)

  • 讨论在下载时更新 os_hash_algo & os_hash_value,当值为 null 时

  • 更新内部 checksum 验证代码以使用 os_hash_value 字段,并在不存在时回退到 checksum 字段

  • 更新 glance 客户端

  • 更新文档

  • 如果 API 准备就绪,则将 os_hash_algo 值添加到 discovery API

依赖项

测试

更新测试以验证镜像属性的正确填充

参考资料