您好,登錄后才能下訂單哦!
這篇“在.NET中如何使用FixedTimeEquals應對計時攻擊”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“在.NET中如何使用FixedTimeEquals應對計時攻擊”文章吧。
在計算機安全中,計時攻擊(Timing attack)是旁道攻擊 (Side-channel attack) 的一種,而旁道攻擊是根據計算機處理過程發出的信息進行分析,包括耗時,聲音,功耗等等,這和一般的暴力破解或者利用加密算法本身的弱點進行攻擊是不一樣的。
假如您有一個后端 webapi, GetConfig 接口用來獲取配置信息,調用時需要在 Header 中傳入一個秘鑰,然后判斷是否正確并進行返回,如下
X-Api-Key: x123
[HttpGet] public IActionResult GetConfig() { var key = Request.Headers["X-Api-Key"].FirstOrDefault(); if (key != "x123") { return Unauthorized(); } return Ok(configuration); }
注意,這里我們為了判斷兩個字符串相等,通常會使用 == 或者 != , 實際上背后使用了 String 的 Equals() 方法,如下
// Determines whether two Strings match. public static bool Equals(string? a, string? b) { if (object.ReferenceEquals(a, b)) { return true; } if (a is null || b is null || a.Length != b.Length) { return false; } return EqualsHelper(a, b); }
而內部又使用了 SequenceEqual() 方法
[MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool EqualsHelper(string strA, string strB) { Debug.Assert(strA != null); Debug.Assert(strB != null); Debug.Assert(strA.Length == strB.Length); return SpanHelpers.SequenceEqual( ref Unsafe.As<char, byte>(ref strA.GetRawStringData()), ref Unsafe.As<char, byte>(ref strB.GetRawStringData()), ((uint)strA.Length) * sizeof(char)); }
大概的邏輯是,先判斷兩個字符串長度是否一致,如果不是,直接返回 false,然后循環字符串進行逐位對比,一旦發現不相同,直接返回 false,偽代碼如下
public bool Equals(string str1, string str2) { if (str1.Length != str2.Length) { return false; } for (var i = 0; i < str1.Length; i++) { if (str1[i] != str2[i]) { return false; } } return true; }
這里有一個問題是,如果字符串第一位不相同,直接就返回 false,如果最后一位不相同,那就需要遍歷到最后,然后返回 false。不一樣的字符串,計算的時長可能不一致。
假如用戶知道了我們的秘鑰的固定長度是 4 位。
GET /GetConfig X-Api-Key:a000 Cost: 2ns
本次耗時了 2ns, 接下來又輸入 b000, c000....
GET /GetConfig X-Api-Key:b000 Cost: 2ns GET /GetConfig X-Api-Key:c000 Cost: 2ns ... GET /GetConfig X-Api-Key:x000 Cost: 4ns
直到輸入了 x000, 發現其他的耗時都是 2ns, 而這里是 4ns,大概率判定第一位是 x。
注意,這里的測試進行了放大,可能每個 case 分別調用了 100 次,然后統計了 P50(中位數)得出的結果。
然后用同樣的方法,測試第二位,第三位....., 最終破解拿到了秘鑰。
雖然看上去有點扯,但確實是真實存在的,包括大名鼎鼎的針對 TLS 的 Lucky 13 攻擊,有興趣的同學可以看一下。在安全性要求比較高的場景中,確實要考慮到計時攻擊,當涉及到安全時,還是寧可信其有。
所以我們的算法的執行耗時應該是固定的,不應該在不匹配時,就立即返回,我們嘗試改造一下代碼
public bool Equals(string str1, string str2) { if (str1.Length != str2.Length) { return false; } bool reult = true; for (var i = 0; i < str1.Length; i++) { if (str1[i] != str2[i]) { reult = false; } } return reult; }
不管怎么樣,都會遍歷完整個字符串,然后返回結果,看上去沒什么問題,時間總是固定的,但在現代的 CPU 和 .NET 上卻不是的,因為我們要考慮到分支預測,特別是 if 條件。
好吧,那我們調整一下代碼
public bool Equals(string str1, string str2) { if (str1.Length != str2.Length) { return false; } bool reult = true; for (var i = 0; i < str1.Length; i++) { reult &= str1[i] == str2[i]; } return reult; }
我們用了運算符 &,來代替 If, 只有全部為 true 時,才會返回 true,其中任意一個字符不匹配,就會返回 false,看上去不錯。
但是,還有一些問題,對于bool類型的 result (true/false), 我們的 .NET JIT 和 x86 指令執行仍然會進行一些優化,我們再調整一下代碼
public bool Equals(string str1, string str2) { if (str1.Length != str2.Length) { return false; } int reult = 0; for (var i = 0; i < str1.Length; i++) { reult |= str1[i] ^ str2[i]; } return reult == 0; }
我們把 bool 改成了 int 類型,然后使用了運算符 ^ 和 |,同樣的,只有字符串全部匹配時,result 為 0,,才會返回 true, 其中任意一個不匹配,result 就不為 0,會返回 false。
最后,為了防止 JIT 對我們的代碼進行其他的優化,我們可以加一個特性,告訴 JIT 不要管它,就像這樣
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] public bool Equals(string str1, string str2) { if (str1.Length != str2.Length) { return false; } int reult = 0; for (var i = 0; i < str1.Length; i++) { reult |= str1[i] ^ str2[i]; } return reult == 0; }
上面我們實現了一個針對字符串比較的固定時間的算法,來應對計時攻擊。
實際上, 從 .NET Core 2.1 開始就已經做了內置支持,我們可以直接使用 FixedTimeEquals 方法, 看一下它的實現
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] public static bool FixedTimeEquals(ReadOnlySpan<byte> left, ReadOnlySpan<byte> right) { if (left.Length != right.Length) { return false; } int length = left.Length; int accum = 0; for (int i = 0; i < length; i++) { accum |= left[i] - right[i]; } return accum == 0; }
現在用起來也很方便:
var result = CryptographicOperations.FixedTimeEquals( Encoding.UTF8.GetBytes(str1), Encoding.UTF8.GetBytes(str2) );
以上就是關于“在.NET中如何使用FixedTimeEquals應對計時攻擊”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。