查看“计时攻击”的源代码
←
计时攻击
跳到导航
跳到搜索
因为以下原因,您没有权限编辑本页:
您所请求的操作仅限于该用户组的用户使用:
用户
您可以查看和复制此页面的源代码。
https://www.douyin.com/user/MS4wLjABAAAAILXvdPy5GrOzGHcjFPWkqgqZY2ELEcTJDz3oTlin47c?modal_id=7173248385904938275 Timing Attack === 安全的实现(计时攻击无效): === <syntaxhighlight lang="java"> public class Test { private boolean safeEqual(String a, String b) { if (a.length() != b.length()){ return false; } int equal = 0; for (int i = 0; i < a.length(); i++){ equal |= a.charAt(i) ^ b.charAt(i); } return equal == 0; } } </syntaxhighlight>上面是判断两个字符串内容是否相同的实现,乍一看有点奇怪: 一开始先判断字符串长度是否相等,不相等直接返回。 之后遍历字符串,对每一位通过异或操作来比较,将每次的结果和 equal 变量进行或运算,如果两个字符串相等,最后存储累积的变量 equal 肯定为0,否则为1。 整体逻辑上是没什么问题,但是效率不够好,完全可以进一步优化——在遍历过程中,如果发现有一位不同就可以直接返回,而不是全部遍历一遍。 似乎可以优化成: === 不安全的实现 === <syntaxhighlight lang="java"> public class Test1 { private boolean safeEqual(String a, String b) { if (a.length() != b.length()){ return false; } for (int i = 0; i < a.length(); i++){ int equal = a.charAt(i) ^ b.charAt(i); if (equal !=0 ) { return false; } } return true; } } </syntaxhighlight> 但 JDK 中也有一个类似的实现(不安全的比较):<syntaxhighlight lang="java"> package java.security; …… public abstract class MessageDigest extends MessageDigestSpi { …… public static boolean isEqual(byte[] digesta, byte[] digestb) { if (digesta == digestb) return true; if (digesta == null || digestb == null) { return false; } int lenA = digesta.length; int lenB = digestb.length; if (lenB == 0) { return lenA == 0; } int result = 0; result |= lenA - lenB; // time-constant comparison for (int i = 0; i < lenA; i++) { // If i >= lenB, indexB is 0; otherwise, i. int indexB = ((i - lenB) >>> 31) * i; result |= digesta[i] ^ digestb[indexB]; } return result == 0; } …… </syntaxhighlight>注意注释 “time-constant comparison”(常量时间比较)。 === 现在来说说这两种实现有什么区别 === ==== 不安全的实现 ==== 假设当前使用的是不安全的 equal 方法,比较的两个字符串是 用户输入密码 和 真正正确的密码,真正的密码是 “password”, 采用穷举的暴力破解方案时: 首先会不断地枚举第一位—— {| class="wikitable" |axxxxxxx 1ms |bxxxxxxx 3ms |cxxxxxxx 5ms |- |dxxxxxxx 4ms |exxxxxxx 15ms |fxxxxxxx 7ms |- | colspan="3" |…… |- |yxxxxxxx 5ms |zxxxxxxx 7ms | |} 最终通过统计发现 “exxxxxxx”的运行时间比其他密码的尝试消耗时间长,很可能就是其他密码在判断第一位不同时方法就返回了 {| class="wikitable" !a !x !x !x !x !x !x !x |- !↑ ! ! ! ! ! ! ! |} 而 e 开头的字符串要判断到第二位时才返回: {| class="wikitable" !p !x !x !x !x !x !x !x |- ! !↑ ! ! ! ! ! ! |} 这样攻击者就能判断出字符串的第一位很可能是 p,然后再不断一位一位迭代下去,最终破解出密码。 ==== 安全的现实 ==== 而当调用安全的实现时:就算两个文本内容不想等,但每一次两个字符串的比对耗费的时间都会是一样的,这样就可以防止攻击者通过大量的改变输入并通过统计运行时间来暴力破解出要比较的字符串。 === 存疑 === 这个例子不太合适:现在基本没有明文密码的比对(都是MD5+salt),暴力MD5碰撞也要能够预知什么样的字典可以暴力MD5碰撞。 计时攻击对于BS结构,这种基于网络的验证,网络环境(网速)不是恒定的,服务器端的字符串比对和 HTTP请求 的时长上下浮动比起来实在不算什么。 有没有别的更合适的例子? 本地 MD5 摘要的比较就是,所以 security 包里的实现是安全的。 似乎也有人对 openssl 的计时攻击成功了 https://eprint.iacr.org/2016/224.pdf
返回至
计时攻击
。
导航菜单
个人工具
登录
名字空间
页面
讨论
变种
视图
阅读
查看源代码
查看历史
更多
搜索
导航
首页
Spring Boot 2 零基础入门
Spring Cloud
Spring Boot
设计模式之禅
VUE
Vuex
Maven
算法
技能树
Wireshark
IntelliJ IDEA
ElasticSearch
VirtualBox
软考
正则表达式
程序员精讲
软件设计师精讲
初级程序员 历年真题
C
SQL
Java
FFmpeg
Redis
Kafka
MySQL
Spring
Docker
JMeter
Apache
Linux
Windows
Git
ZooKeeper
设计模式
Python
MyBatis
软件
数学
PHP
IntelliJ IDEA
CS基础知识
网络
项目
未分类
MediaWiki
镜像
问题
健身
国债
英语
烹饪
常见术语
MediaWiki帮助
工具
链入页面
相关更改
特殊页面
页面信息