<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          在 .NET 中使用 FixedTimeEquals 應(yīng)對計時攻擊

          共 1434字,需瀏覽 3分鐘

           ·

          2022-06-10 08:27

          ? 計時攻擊??

          在計算機安全中,計時攻擊(Timing attack)是旁道攻擊 (Side-channel attack) 的一種,而旁道攻擊是根據(jù)計算機處理過程發(fā)出的信息進(jìn)行分析,包括耗時,聲音,功耗等等,這和一般的暴力破解或者利用加密算法本身的弱點進(jìn)行攻擊是不一樣的。

          ? 舉個例子??

          假如您有一個后端 webapi, GetConfig 接口用來獲取配置信息,調(diào)用時需要在 Header 中傳入一個秘鑰,然后判斷是否正確并進(jìn)行返回,如下

          X-Api-Key:?x123
          [HttpGet]
          public?IActionResult?GetConfig()
          {
          ????var?key?=?Request.Headers["X-Api-Key"].FirstOrDefault();
          ????if?(key?!=?"x123")
          ????{
          ????????return?Unauthorized();
          ????}

          ????return?Ok(configuration);
          }??

          注意,這里我們?yōu)榱伺袛鄡蓚€字符串相等,通常會使用 == 或者 != , 實際上背后使用了 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);
          }

          而內(nèi)部又使用了 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,然后循環(huán)字符串進(jìn)行逐位對比,一旦發(fā)現(xiàn)不相同,直接返回 false,偽代碼如下

          public?bool?Equals(string?str1,?string?str2)
          {
          ????if?(str1.Length?!=?str2.Length)?
          ????{
          ????????return?false;
          ????}?

          ????for?(var?i?=?0;?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, 發(fā)現(xiàn)其他的耗時都是 2ns, 而這里是 4ns,大概率判定第一位是 x。

          注意,這里的測試進(jìn)行了放大,可能每個 case 分別調(diào)用了 100 次,然后統(tǒng)計了 P50(中位數(shù))得出的結(jié)果。

          然后用同樣的方法,測試第二位,第三位....., 最終破解拿到了秘鑰。

          ? 使用固定時間的算法??

          雖然看上去有點扯,但確實是真實存在的,包括大名鼎鼎的針對 TLS 的 Lucky 13 攻擊,有興趣的同學(xué)可以看一下。在安全性要求比較高的場景中,確實要考慮到計時攻擊,當(dāng)涉及到安全時,還是寧可信其有。

          所以我們的算法的執(zhí)行耗時應(yīng)該是固定的,不應(yīng)該在不匹配時,就立即返回,我們嘗試改造一下代碼

          public?bool?Equals(string?str1,?string?str2)
          {
          ????if?(str1.Length?!=?str2.Length)
          ????{
          ????????return?false;
          ????}

          ????bool?reult?=?true;

          ????for?(var?i?=?0;?i?????{
          ????????if?(str1[i]?!=?str2[i])
          ????????{
          ????????????reult?=?false;
          ????????}
          ????}

          ????return?reult;
          }

          不管怎么樣,都會遍歷完整個字符串,然后返回結(jié)果,看上去沒什么問題,時間總是固定的,但在現(xiàn)代的 CPU 和 .NET 上卻不是的,因為我們要考慮到分支預(yù)測,特別是 if 條件。

          好吧,那我們調(diào)整一下代碼

          public?bool?Equals(string?str1,?string?str2)
          {
          ????if?(str1.Length?!=?str2.Length)
          ????{
          ????????return?false;
          ????}

          ????bool?reult?=?true;

          ????for?(var?i?=?0;?i?????{?
          ???????reult?&=?str1[i]?==?str2[i];?
          ????}

          ????return?reult;
          }

          我們用了運算符 &,來代替 If, 只有全部為 true 時,才會返回 true,其中任意一個字符不匹配,就會返回 false,看上去不錯。

          但是,還有一些問題,對于bool類型的 result (true/false), 我們的 .NET JIT 和 x86 指令執(zhí)行仍然會進(jìn)行一些優(yōu)化,我們再調(diào)整一下代碼

          public?bool?Equals(string?str1,?string?str2)
          {
          ????if?(str1.Length?!=?str2.Length)
          ????{
          ????????return?false;
          ????}

          ????int?reult?=?0;

          ????for?(var?i?=?0;?i?????{?
          ???????reult?|=?str1[i]?^?str2[i];?
          ????}

          ????return?reult?==?0;
          }

          我們把 bool 改成了 int 類型,然后使用了運算符 ^ 和 |,同樣的,只有字符串全部匹配時,result 為 0,,才會返回 true, 其中任意一個不匹配,result 就不為 0,會返回 false。

          最后,為了防止 JIT 對我們的代碼進(jìn)行其他的優(yōu)化,我們可以加一個特性,告訴 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?????{?
          ???????reult?|=?str1[i]?^?str2[i];?
          ????}

          ????return?reult?==?0;
          }?

          上面我們實現(xiàn)了一個針對字符串比較的固定時間的算法,來應(yīng)對計時攻擊。

          實際上, 從 .NET Core 2.1 開始就已經(jīng)做了內(nèi)置支持,我們可以直接使用 FixedTimeEquals 方法, 看一下它的實現(xiàn)

          [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?????{
          ????????accum?|=?left[i]?-?right[i];
          ????}

          ????return?accum?==?0;
          }

          現(xiàn)在用起來也很方便:

          var?result?=?CryptographicOperations.FixedTimeEquals(
          ???Encoding.UTF8.GetBytes(str1),?Encoding.UTF8.GetBytes(str2)
          );?

          ? 總結(jié)??

          在安全性比較高的場景中,應(yīng)該要考慮到計時攻擊,可以使用固定時間的算法來應(yīng)對。在其他的開發(fā)語言中,也都有本文中類似的算法,而在 .NET 中,現(xiàn)在我們可以直接使用 CryptographicOperations.FixedTimeEquals。



          瀏覽 19
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日本一区二区三区在线观看视频 | 一本色道久久综合无码人妻软件 | 欧美福利视频导航 | 波多野结衣做爱视频 | 久久欠久久久久久九秃大奖励 |