計時攻擊
Timing Attack ,時序攻擊,是一種側信道攻擊,攻擊者嘗試分析加密算法的時間執行順序來推導出密碼。每個邏輯運算都需要執行時間,但是 根據不同的輸入值,精確測量執行時間,根據執行時間反推出密碼的一些區域 。
簡單理解,就是破解密碼的人,通過不同的輸入策略組合嘗試去驗證密碼,得到不同的執行時間,從而反推出密碼的區域,降低破解密碼的難度。
下面可以使用Java簡單描述一下。
我們看一下Java中的String equals方法(Java17)
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
return (anObject instanceof String aString)
&& (!COMPACT_STRINGS || this.coder == aString.coder)
&& StringLatin1.equals(value, aString.value);
}
//StringLatin1.equals
@IntrinsicCandidate
public static boolean equals(byte[] value, byte[] other) {
if (value.length == other.length) {
for (int i = 0; i < value.length; i++) {
if (value[i] != other[i]) {
return false;
}
}
return true;
}
return false;
}
以上方法中字符串比較一旦遇到不同的字符,那么就直接返回失敗。
那么看一下下面的3行代碼的執行時間。
"adfg".equals("abcd");
"abfg".equals("abcd");
"abcg".equals("abcd");
以上的3行字符串比較方法執行時間是不同的。
執行時間: 第一行 < 第二行 < 第三行
假如現在我們要猜出另外一個字符串,那么如果我們用暴力窮舉猜測字符串,則 根據不同的字符串組合,得到的執行時間是不一樣的,那么根據不同的執行時間分析,就可以知道前面幾個字符串是否正確,從而縮小范圍 。
以上是一個計時攻擊的簡單例子,實際密碼加密,公私鑰加密算法是比較復雜的,但是也要考慮計時攻擊的影響。
多年前斯坦福的教授們專門針對這些問題發表過相關的論文,下面這篇于2005年發表在《Computer networks》的期刊論證了遠程網絡計時攻擊的可能性。
計時攻擊的防御
那么對于計時攻擊這種要如何防止呢, 大部分的做法是使單向加密,或者密碼驗證的算法執行時間不會隨著輸入值的不同而規律變化 。換句話說就是 不同的輸入值的執行時間相同 ,或者 執行時間隨機分布 , 無法規律判斷 。
2009年jdk6的一個升級中就有相關的優化來防止計時攻擊。MessageDigest是java.security包里面的類,主要用于SHA或 MD5 等密碼上安全的報文摘要功能而設計。最終會用到其equals方法。而這個改動就是針對equals方法。
其中關鍵的改動就是判斷字符串相等時,不再看到不相等的字符就返回false。而是 對比完所有的字符之后再返回結果 。這樣代碼的執行時間就大致相同。
同時2021年jdk8的補丁也有相關的優化,
乍一看上面的代碼已經比較完美了。但是。。。。
密碼字符串的信息 還有長度信息
還是有坑哈。。。。。
其實上述中的代碼還有一個問題,就是 不同長度的字符串的執行時間也不一樣 ,那么如果我搞一輪不同長度字符串窮舉之后,可以 根據運行計算時間的不同可以推出密碼的長度 。再進行破解相對容易一點。
再看如今Java17中的這個方法, 長度不同時也不會立馬返回false ,而是照常執行整個代碼,這樣就避免了根據執行時間先得到密碼的長度。
//MessageDigest
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;
}
小結
以上就是計時攻擊的一些簡單內容,網絡安全中的冰山一角。再次致敬這些維護JDK源碼的大師們!
-
JAVA
+關注
關注
19文章
2960瀏覽量
104562 -
字符
+關注
關注
0文章
232瀏覽量
25178 -
代碼
+關注
關注
30文章
4753瀏覽量
68368 -
加密算法
+關注
關注
0文章
211瀏覽量
25531
發布評論請先 登錄
相關推薦
評論