来自计时攻击的一课(或者,不要使用 MessageDigest.isEquals )

简介:

仅中文 | 中英文对照 | 仅英文 | 打印此文章
对于某些打算写一个安全的密码系统的人的角度来说,计时攻击相当可怕。它工作原理是依赖于程序员的最佳本能—不要做多余的工作,而这给攻击者得到一个统计101教科书(而这能很好的得到您应用程序的核心)。

这东西是怎么工作的呢?

简言之,一个计时攻击使用一个统计学的分析关于您的应用程序使用多长时间去做某些事情,这样就能知道关于应用程序操作的数据。对HMACs而言,这意味着使用一定数量的值(您的应用程序花掉的时间的值)和一个改定的计算值比较,这样就能得到这个计算值的信息。

瑞新
瑞新
翻译于 4年前
1人顶
顶 翻译得不错哦!
拿 最近Nate Lawson发现的Keyczar 漏洞 来说。他能够通过一个简单的冲突不等式算法(比较一个候选HMAC时间摘要和Keyczar计算时间摘要)破解Keyczar的事实。

这是攻击代码使用Python:

return self.Sign(msg) == sig_bytes
使用Java:

return Arrays.equals(hmac.doFinal(), sigBytes);
如加密计算摘要一样,如果没有字节就马上返回一个值;如果有15个字节,则返回15次比较后的一个值。虽然他们的不同是微秒级别的,但是已经能够得到足够的尝试-这通常容易在web应用程序中整理(有多少伴随错误会话cookies的请求)-随机的噪音会变得非常容易整理,会按照一定的规则分布倾斜,只留下真正的信号。

瑞新
瑞新
翻译于 4年前
1人顶
顶 翻译得不错哦!
这似乎并没有那么糟
但是恰恰相反。

我可以选择一个我想被授权的消息 —它描述的是一个特定用户的会话cookie—然后计算256位可能的值:

0000000000000000000000000000000000000000
0100000000000000000000000000000000000000
0200000000000000000000000000000000000000
... 省略 250 ...
FD00000000000000000000000000000000000000
FE00000000000000000000000000000000000000
FF00000000000000000000000000000000000000
我计算这些值,直到我找到—A100000000000000000000000000000000000000—这个值使用的时间明显比别的使用的时间超过一小部分的微秒值. 然后我马上直到这个消息的HMAC的第一个的字节很大可能A1. 重复这个过程计算余下的19个字节, 然后突然我使用登陆进去了你的账号。

瑞新
瑞新
翻译于 3年前
1人顶
顶 翻译得不错哦!
你不可能进行衡量,你能吗?

现在开始, 大部分人开始思考关于在web应用程序中衡量两个数组的比较的计时发生的几率, 考虑所有的路由, 解析器, 服务器, 代理, 等等.

根据 Crosby et al的 计时攻击的机会和限制:

我们已经证明, 尽管互联网会有很大的时间延迟, 我们还是可以可靠地分辨低至20µs远程时间差异. 如果局域网的话会有更小的时间延迟, 允许我们区分远程时间差异100ns(甚至更小). 时间差异只要有数百或数千次测量就能够更加精确.

瑞新
瑞新
翻译于 3年前
2人顶
顶 翻译得不错哦!
所以.几乎数百微秒就完成了成千上万的计算.谁敢断定网络延迟会变得更差而不是更好?

最糟糕的情况下进行一个HMAC 需要请求20×256×n 计算, 其他n 是计算请求计算需求确认的单个字节的数量. 所以需要 5,000,000倍数的请求. 在每秒10个请求的情况下(几乎难以察觉),你可以不到一个星期就可以完成.

这种攻击方式需要有一些计划和分析, 但是是可行的.

瑞新
瑞新
翻译于 3年前
1人顶
顶 翻译得不错哦!
好了,废话少说,现在怎么做呢?
您可以使用constant-time算法,用来替换variable-time算法比较加密. Lawson 提供了Python的实现如下:

def is_equal(a, b):
    if len(a) != len(b):
        return False

    result = 0
    for x, y in zip(a, b):
        result |= x ^ y
    return result == 0
Java 实现,如下:

public static boolean isEqual(byte[] a, byte[] b) {
    if (a.length != b.length) {
        return false;
    }

    int result = 0;
    for (int i = 0; i < a.length; i++) {
      result |= a[i] ^ b[i]
    }
    return result == 0;}

耶!问题解决了,是吗?
Oh, 如果仅仅是上面这样,那么是的。

检查在最近Java 6.0 Update 15更新的 java.security.MessageDigestas中的代码,如下:

/**  * Compares two digests for equality. Does a simple byte compare.  *  * @param digesta one of the digests to compare.  *  * @param digestb the other digest to compare.  *  * @return true if the digests are equal, false otherwise.  */public static boolean isEqual(byte digesta[], byte digestb[]) {
    if (digesta.length != digestb.length)
        return false;

    for (int i = 0; i < digesta.length; i++) {
        if (digesta[i] != digestb[i]) {
            return false;
        }
    }
    return true;}

瑞新
瑞新
翻译于 3年前
1人顶
顶 翻译得不错哦!

等待什么

Yep. 一个字节一个字节的比较;返回第一个不相等的. 但是不是我们需要的.

我在这里直接的说: 任何java程序(通过MessageDigest.isEqualis比较客户端提供数据和加密值比较的) 都是容易受到计时攻击的. 这里包括 HMACs, 解密结果, 等等.

在2009年7月22号,我把向sun提交了这个问题. 就是问题: # 6863503, 由于安全问题,这是不可以公开的.除了包含问题票号的自动回复邮件,我到目前为止没有从sun听到关于这个问题的任何回复. 在我们问题报告中, 我表达了我的意图:我将会遵守 RFPolicy, 内容:

如果维护者在5个工作日内没有和问题发现者进行任何联系, 这个问题发现者将会选择公开这个问题. 维护者负责定期提供状态更新 (关于解决这个问题) 最短每五天一次.

所以我在这里,完全公开在这个最大的编程平台上的一个相当大的漏洞. 如果我不说那就太可怕了.

瑞新
瑞新
翻译于 3年前
1人顶
顶 翻译得不错哦!
长话短说

像上面的例子那样,使用等值时间算法来取代您使用的MessageDigest.isEqual.

每次你比较两个值, 问问你自己: 如果有人知道这两个值,他们可以做什么? 如果答案是有意义的,使用等值时间算法来比较.

附注

如果更多的加密类库能够有更好的封装,这个问题会小的多. 一个HMAC不仅仅是一系列的字符和字节—为什么这么说? 为什么这么关键的加密算法会出现这种情况的纰漏?

谢谢

Nate Lawson的Keyczar促使我思考出怎么计时攻击我自己的代码.他的何时密码攻击 讲述了需要请给每个人查看编译器的请求.

瑞新
瑞新
翻译于 3年前
1人顶
顶 翻译得不错哦!
2009年8月13号更新

sophacles 在 黑客上指出, 我更多的重构推荐的 constant-time 算法, 并且通过返回状态为布尔值的更加简短表达式,介绍更多计时攻击漏洞的细节. 而这个算法的已经通过这次更新解决了.

2009年12月3号更新

关于MessageDigestwas的计时攻击漏洞已经在Java SE 6 Update 17更新中解决。

文章转载自 开源中国社区 [http://www.oschina.net]

相关文章
|
算法 数据安全/隐私保护
对称密钥加密算法和公开密钥加密算法有什么区别
【4月更文挑战第19天】对称密钥和公开密钥加密算法各有特点:对称密钥加密速度快,适用于大量数据,但密钥管理困难;公开密钥加密安全性高,密钥管理方便,但速度慢,常用于数字签名和身份验证。两者在不同场景下有不同优势。
859 6
|
缓存 运维 监控
10分钟带你了解 Linux 系统中的 Top 命令
`top`命令是Linux系统中用于实时监控系统资源利用率的工具,展示CPU、内存使用情况及进程状态。启动`top`只需在终端输入`top`。默认按CPU使用率排序,可通过`P`、`M`、`T`键改变排序。使用`k`键可结束进程,`d`键调整刷新率,`q`键退出。输出信息包括系统负载、进程状态、内存使用等。通过进程列表,可以观察到每个进程的CPU和内存占用、用户、运行时间等。了解`top`能帮助测试工程师排查性能问题。
|
3月前
|
监控 Java 数据挖掘
利用Jmeter工具进行HTTP接口的性能测试操作
基础上述步骤反复迭代调整直至满足预期目标达成满意水平结束本轮压力评估周期进入常态监控阶段持续关注系统运转状态及时发现处理新出现问题保障服务稳定高效运作
532 0
|
SQL 关系型数据库 MySQL
mysql用户、权限管理
mysql用户、权限管理
244 0
|
9月前
|
缓存 Ubuntu Linux
Apt软件包管理工具使用指南
前言 在Linux系统中,apt(Advanced Package Tool)是基于Debian/Ubuntu发行版广泛使用的软件包管理工具之一。它为用户提供了便捷的软件包安装、更新、删除等功能,是管理软件包的重要手段。本文将详细介绍apt的常用命令及其使用方法,帮助用户更好地管理和维护系统中的软件包。
910 2
|
前端开发 JavaScript
去除router-link中的下划线
这篇文章介绍了如何在Vue.js中去除`<router-link>`元素的默认下划线样式,通过全局CSS覆盖来保持页面样式的整洁。
去除router-link中的下划线
|
存储 运维 架构师
Netty API网关实操系列(二)
Netty API网关实操系列(二)
|
Java Spring 开发者
Spring 框架配置属性绑定大比拼:@Value 与 @ConfigurationProperties,谁才是真正的王者?
【8月更文挑战第31天】Spring 框架提供 `@Value` 和 `@ConfigurationProperties` 两种配置属性绑定方式。`@Value` 简单直接,适用于简单场景,但处理复杂配置时略显不足。`@ConfigurationProperties` 则以类级别绑定配置,简化代码并更好组织配置信息。本文通过示例对比两者特点,帮助开发者根据具体需求选择合适的绑定方式,实现高效且易维护的配置管理。
330 0
|
存储 算法 Java
Java的内存模型与垃圾回收机制
Java的内存模型与垃圾回收机制
180 3
|
前端开发 Java Spring
SpringBoot通过拦截器和JWT令牌实现登录验证
该文介绍了JWT工具类、匿名访问注解、JWT验证拦截器的实现以及拦截器注册。使用`java-jwt`库生成和验证JWT,JwtUtil类包含generateToken和verifyToken方法。自定义注解`@AllowAnon`允许接口匿名访问。JwtInterceptor在Spring MVC中拦截请求,检查JWT令牌有效性。InterceptorConfig配置拦截器,注册并设定拦截与排除规则。UserController示例展示了注册、登录(允许匿名)和需要验证的用户详情接口。
2185 1