以下の抜粋は、ハッシュデータ構造で使用される非ランダムハッシュ関数によるサービス拒否(DoS)攻撃の可能性を説明する 記事 からのものです。
[…]基礎となるハッシュアルゴリズムで予測可能な衝突を利用することで、この条件を活用できます。
それを検証するために、OracleのJava HashMapのリファレンス実装を実行し、実際に使用されている静的ハッシュ関数を見つけました。
static int hash(int h) {
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
トピックに関する別の 紙 は次のように語っています:
Tomcat6.0.32サーバーは2MBの衝突するキーの文字列を約44分のi7CPU時間で解析するため、約6 kbit/sの攻撃者は、1つのi7コアを常にビジー状態に保つことができます。攻撃者がギガビット接続を使用している場合、攻撃者は約100.000i7コアをビジー状態に保つことができます
この脆弱性をどのように防ぐことができますか。さらに、非常に多くのソフトウェアで、この実装に依存するオープンソース(Tomcatなど)を使用しています。
ブログのコメントフォームがパラメータ(first_name、last_name、comment)を投稿パラメータとして受け入れるとします。内部的には、TomcatはこれらのパラメーターをHashMapとして格納します。
このHashMapの論理構造は次のようになります-
"first_name" --> "Sripathi"
"last_name" --> "Krishnan"
"comment" ---> "DoS using poor Hashes"
しかし、物理的構造は異なります。キーは最初にhashCodeに変換され、次にhashCodeが配列インデックスに変換されます。
したがって、理想的な物理構造は-になります。
0 --> "Sripathi"
1 --> "Krishnan"
2 --> "DoS using poor Hashes"
しかし、可能なキーは無限です。したがって、ある時点で、2つのキーが同じハッシュコードを持つようになります。これはハッシュ衝突になります。
衝突があると、物理構造は次のようになります。
0 --> "Sripathi", "Krishnan"
1 --> Empty
2 --> "DoS using poor hashes"
ハッシュの衝突がある場合、新しいエントリを挿入するということは、単一のハッシュ「バケット」のすべての要素を順次繰り返して、マップにすでに存在するかどうかを確認することを意味します。すべての要素が同じ値にハッシュされる場合、1つの要素を挿入するとO(n)複雑さに近づく可能性があります。この最悪の場合にn要素を挿入すると、O(n * n)の複雑さになります。
つまり、同じhashCodeを持つ何千ものキーを挿入すると、サーバーは多くのCPUサイクルを必要とします。
Javaでは、「Aa」と「BB」のハッシュコードは同じです。
「EquivalentSubstrings」というプロパティがあるため、これら2つの文字列から始めるだけで、同じハッシュコードで他の複数の文字列を生成できます。
最初の反復:「AAAA」、「AABb」、「BbAA」、「BbBb」は同じハッシュコードを持っています
これで、同じハッシュコードを持つ4つの文字列ができました。それらを並べ替えて、同じハッシュコードを持つ16個の文字列を生成できます。例えば :
"AaAaAaAa", "AaAaBBBB", "AaAaAaBB", "AaAaBBAa",
"BBBBAaAa", "BBBBBBBB", "BBBBAaBB", "BBBBBBAa",
"AaBBAaAa", "AaBBBBBB", "AaBBAaBB", "AaBBBBAa",
"BBAaAaAa", "BBAaBBBB", "BBAaAaBB", "BBAaBBAa",
これらの16個の文字列はすべて同じハッシュコードを持っています。
これで、これらの16個の文字列を取得して、同じハッシュコードを持つ256個の文字列を生成できます。
つまり、正確なハッシュコードを持つ文字列の大規模なセットを生成するのは非常に簡単です。
これは単なるPOSTリクエストであるため、攻撃者は無実のブラウザを使用してサーバーを攻撃することもできます。クロスサイトスクリプティングの脆弱性があるWebサイトを見つけ、コードを埋め込んでPOSTリクエストしてから、ソーシャルエンジニアリングを使用して、できるだけ多くのユーザーにリンクを広げます。
一般に、基盤となるプラットフォームはこれを修正できません。これは、アプリケーションフレームワークの問題と見なされます。言い換えれば、TomcatはOracle/Sunではなく、これを修正する必要があります。
考えられる修正は次のとおりです。
POSTパラメータの数を制限する-Tomcat 6.0.35+に新しいパラメータがあります maxParameterCount。デフォルト値は10,000です。機能を損なわない限り、低いほど良いです。
POST requestのサイズを制限する-攻撃が機能するためには、ペイロードが巨大である必要があります。デフォルトPOSTは2MBです。これを200KBに減らすと、この攻撃の効果が低下します。TomcatのパラメータはmaxPostSizeです。
Webアプリケーションファイアウォール-Webアプリケーションファイアウォールがある場合は、疑わしいと思われる要求をブロックするように構成できます。これは事後対応策ですが、上記の解決策のいずれかを使用できない場合に備えておくと便利です。
参考までに--Tomcatのドキュメントはこちら- http://Tomcat.Apache.org/Tomcat-6.0-doc/config/http.html
最も簡単な解決策は、Tomcatの固定バージョンにアップグレードすることです。ただし、Tomcatの人々が何を変更する必要があるかについての詳細を知りたいと思います。
この攻撃は、ハッシュデータ構造の一般的な実装の詳細を悪用することによって機能します-リンクリストを使用して、ハッシュが同じであるすべての値を保持します。このリンクリストに値を追加すると、リストのサイズが大きくなるため非効率的です。攻撃者は、衝突するハッシュを生成することがわかっている値のリストを作成して、この非効率的な動作を強制する可能性があります。これから保護するために、いくつかのオプションがあります。
衝突を防ぐ-ハッシュ関数に(疑似)ランダム要素を含めることで、攻撃者が衝突する値を生成するのを防ぎます。 Perlはこれを長い間行ってきました。
バケットにはリンクリスト以外のものを使用してください。リンクリストにN個のアイテムを挿入するとN ^ 2増加するため、攻撃は機能します。挿入時にNlogNの増加がある平衡ツリーまたはその他の構造を使用する場合は、問題を軽減する必要があります。これは、最悪のケースがどれほど悪いかを制限するために、いくつかの最良/平均的なケースのパフォーマンスを犠牲にする可能性があります。
影響を受けるTomcatのバージョンは、指定したリンクに従って、Apache Tomcat <= 5.5.34、<= 6.0.34、<= 7.0.22です。このページには、Apache Tomcat> = 5.5.35、> = 6.0.35、> = 7.0.23が修正バージョンとしてリストされています。
これらのキーを生成するためのpythonコード...まだテストしていませんが、フィードバックを得ることに興味があります:
#!/usr/bin/python
import sys
alphabet = ["Aa","BB"]
def func(str, length):
global alphabet
if(length != 0):
for x in alphabet:
new_str = str+x
func(new_str, length-1)
else:
sys.stdout.write(str+"=&")
for x in range(1,16):
func("",x)
Java HashMap/HashTableは、入力されたエントリがしきい値に達したときに「サイズ変更」操作を実行できます。固定バケットのHashMapがあなたを待っているとは言い難いです。バケットを選択する操作のため、2つのステップがあります。1つは指定されたキーのハッシュ値を取得することです。もう1つの主要なステップは、バケットの合計サイズを使用した剰余操作です(サイズは「サイズ変更」によって変更されています)。