文字列が等しいかどうかを比較するこれらの10行のコードは、私に完全な混乱をもたらします。私を信じていない場合は、ぜひご覧ください。

文字列が等しいかどうかを比較するこれらの10行のコードは、私に完全な混乱をもたらします。私を信じていない場合は、ぜひご覧ください。

コードエイプストーン

文字列が等しいかどうかを比較するこれらの10行のコードは、私に完全な混乱をもたらします。私を信じていない場合は、ぜひご覧ください。

このタイトルを使用してクリックするように促して申し訳ありませんが、それを読んで何かを得ることができるかどうかを確認することをお勧めします。(はい、コメント欄にメッセージを残してください。何もありません。来週末に生放送します**、ハハ、あなたも信じています)

補足:WeChat公式アカウントの改訂は、さまざまなアカウント所有者に大きな影響を与えます。とにかく私は小さな絵なので、背景データからはほとんど影響がありません。読む量自体は哀れです。真実は、絵(交換グループから学んだばかり)です。

まず、コードに直接移動します。


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;
}

上記のコードは、元のバージョン(Scala)に基づいてJavaに翻訳されました。Scalaバージョン(最初にプログラマーの注意を引いたコード)は次のとおりです。


def safeEqual(a: String, b: String) = {
  if (a.length != b.length) {
    false
  } else {
    var equal = 0
    for (i <- Array.range(0, a.length)) {
      equal |= a(i) ^ b(i)
    }
    equal == 0
  }
}

このソースコードを見ると、最初は違和感があります。この関数の機能は、2つの文字列が等しいかどうかを比較することです。まず、「長さが等しくない結果は絶対に等しくないので、すぐに戻る」ということはよく理解されています。
後ろを見て、少し頭を使ってください。曲がっても出入り口がわかります。排他的論理和演算1 ^ 1 = 0、1 ^ 0 = 1、0 ^ 0 = 0を使用して比較してください。各ビット、各ビットが等しい場合、2つの文字列は等しくなければならず、累積XOR値を格納する変数equalは0でなければならず、そうでない場合は1です。

もう一度考えてみませんか?


for (i <- Array.range(0, a.length)) {
  if (a(i) ^ b(i) != 0) // or a(i) != b[i]
    return false
}

パフォーマンスの最適化についてよく話しますが、効率の観点から、特定のビットの結果が異なる(つまり、1)ことがわかっている限り、2つの文字列が等しくないことをすぐに返すことはできないでしょうか。(上記のように)。
がなければならない...
文字列が等しいかどうかを比較するこれらの10行のコードは、私に完全な混乱をもたらします。私を信じていない場合は、ぜひご覧ください。

もう一度考えてみませんか?


メソッド名safeEqualsと組み合わせると、安全性について何か知っているかもしれません。

この記事の冒頭のコードは、Cookie(セッション)内のデータが合法であるかどうかを検証するために使用されるplayframewok(署名の検証を含む)からのものであり、これもこの記事の起源です。

以前は、計算の遅延などで効率を上げる方法を知っていましたが、計算結果が遅れて返ってくるのは今回が初めてです!
見てみましょう。JDKにも同様のメソッドがあります。次のコードはjava.security.MessageDigestから取得されます。


public static boolean isEqual(byte[] digesta, byte[] digestb) {
   if (digesta == digestb) return true;
   if (digesta == null || digestb == null) {
       return false;
   }
   if (digesta.length != digestb.length) {
       return false;
   }

   int result = 0;
   // time-constant comparison
   for (int i = 0; i < digesta.length; i++) {
       result |= digesta[i] ^ digestb[i];
   }
   return result == 0;
}

コメントを参照してください。目的は、一定の時間計算量と比較することです。
しかし、この計算プロセスに費やされる時間が一定でないリスクは何ですか?(バックグラウンドミュージックが頭に浮かびました:「子供、疑問符はたくさんありますか?」)
文字列が等しいかどうかを比較するこれらの10行のコードは、私に完全な混乱をもたらします。私を信じていない場合は、ぜひご覧ください。

真実が明らかにされる


さらに調査して理解した結果、これはタイミング攻撃を防ぐために行われていることがわかりました。(一部の人々はそれをタイミングに変換します***)
文字列が等しいかどうかを比較するこれらの10行のコードは、私に完全な混乱をもたらします。私を信じていない場合は、ぜひご覧ください。

タイミング攻撃(タイミング攻撃)


タイミング***はサイドチャネル***の一種です(または「サイドチャネル攻撃」、サイドチャネル攻撃、略してSCA)。サイドチャネル***は一種のソフトウェアまたはハードウェアの設計上の欠陥であり、一種の欠陥です。邪悪な方法。「***メソッド。
このハッキング方法は、消費電力、タイミング、電磁漏れなどを介してクラッキングの目的を達成することです。多くの物理的に隔離された環境では、驚くほど成功することがよくあります。この新しいタイプのセキュリティの有効性は、暗号解読の従来の数学的方法(百科事典に記載されている)よりもはるかに高くなっています。
このメソッドを使用すると、safeEquals( "abcdefghijklmn"、 "xbcdefghijklmn")(最初の桁のみが異なります)の呼び出しとsafeEquals( "abcdefghijklmn"、 "abcdefghijklmn")(2つの同一の文字列)の呼び出しに同じ時間がかかります。入力統計と実行時間統計の多数の変更により、文字列がブルートフォース攻撃されるのを防ぎます。
例を挙げる

おすすめ

転載: blog.51cto.com/15072927/2607592