HashTableと
HashDoS@yuya_takeyama
Forthe
Beginners
Bya
Beginner
アジェンダ
•ハッシュテーブルとは•PHP におけるハッシュテーブル•PHP における HashDoS
ハッシュテーブルとは•Key から Value を検索•連想配列に使われる•基本的には効率的で高速•最悪の場合はとても非効率に
http://www.is.titech.ac.jp/~kishi/classes/java11/java09.html
PHP における ハッシュテーブル
•HashTable 構造体•複数の Bucket 構造体から成る•順番を保持
typedef struct _hashtable { uint nTableSize; uint nTableMask; uint nNumOfElements; ulong nNextFreeElement; Bucket *pInternalPointer; Bucket *pListHead; Bucket *pListTail; Bucket **arBuckets; dtor_func_t pDestructor; zend_bool persistent; unsigned char nApplyCount; zend_bool bApplyProtection;} HashTable;
typedef struct _hashtable { uint nTableSize; uint nTableMask; uint nNumOfElements; ulong nNextFreeElement; Bucket *pInternalPointer; Bucket *pListHead; Bucket *pListTail; Bucket **arBuckets; dtor_func_t pDestructor; zend_bool persistent; unsigned char nApplyCount; zend_bool bApplyProtection;} HashTable;
テーブルのスロット数
typedef struct _hashtable { uint nTableSize; uint nTableMask; uint nNumOfElements; ulong nNextFreeElement; Bucket *pInternalPointer; Bucket *pListHead; Bucket *pListTail; Bucket **arBuckets; dtor_func_t pDestructor; zend_bool persistent; unsigned char nApplyCount; zend_bool bApplyProtection;} HashTable; 要素数
typedef struct _hashtable { uint nTableSize; uint nTableMask; uint nNumOfElements; ulong nNextFreeElement; Bucket *pInternalPointer; Bucket *pListHead; Bucket *pListTail; Bucket **arBuckets; dtor_func_t pDestructor; zend_bool persistent; unsigned char nApplyCount; zend_bool bApplyProtection;} HashTable;
先頭または
末尾の要素
typedef struct _hashtable { uint nTableSize; uint nTableMask; uint nNumOfElements; ulong nNextFreeElement; Bucket *pInternalPointer; Bucket *pListHead; Bucket *pListTail; Bucket **arBuckets; dtor_func_t pDestructor; zend_bool persistent; unsigned char nApplyCount; zend_bool bApplyProtection;} HashTable;
要素の集まり
ドユコト?
可視化しましょう
<?phphashtable_dump(array(1, 2, 3, 4, 5, 6, 7, 8));/*nTableSize: 8nTableMask: 7nNumOfElements: 8nNextFreeElement: 8pListHead: 0pListTail: 7**arBuckets: 0 => [0, NULL] 1 => [1, NULL] 2 => [2, NULL] 3 => [3, NULL] 4 => [4, NULL] 5 => [5, NULL] 6 => [6, NULL] 7 => [7, NULL]*/
テーブルのスロット数
<?phphashtable_dump(array(1, 2, 3, 4, 5, 6, 7, 8));/*nTableSize: 8nTableMask: 7nNumOfElements: 8nNextFreeElement: 8pListHead: 0pListTail: 7**arBuckets: 0 => [0, NULL] 1 => [1, NULL] 2 => [2, NULL] 3 => [3, NULL] 4 => [4, NULL] 5 => [5, NULL] 6 => [6, NULL] 7 => [7, NULL]*/ 要素数
<?phphashtable_dump(array(1, 2, 3, 4, 5, 6, 7, 8));/*nTableSize: 8nTableMask: 7nNumOfElements: 8nNextFreeElement: 8pListHead: 0pListTail: 7**arBuckets: 0 => [0, NULL] 1 => [1, NULL] 2 => [2, NULL] 3 => [3, NULL] 4 => [4, NULL] 5 => [5, NULL] 6 => [6, NULL] 7 => [7, NULL]*/
先頭または
末尾の要素
<?phphashtable_dump(array(1, 2, 3, 4, 5, 6, 7, 8));/*nTableSize: 8nTableMask: 7nNumOfElements: 8nNextFreeElement: 8pListHead: 0pListTail: 7**arBuckets: 0 => [0, NULL] 1 => [1, NULL] 2 => [2, NULL] 3 => [3, NULL] 4 => [4, NULL] 5 => [5, NULL] 6 => [6, NULL] 7 => [7, NULL]*/
要素の集まり
Bucket 構造体
•値の入れ物•配列内の一要素を表現•二重の双方向リスト
typedef struct bucket { ulong h; uint nKeyLength; void *pData; void *pDataPtr; struct bucket *pListNext; struct bucket *pListLast; struct bucket *pNext; struct bucket *pLast; const char *arKey;} Bucket;
キーの数値または
キー文字列のハッシュ値ここあんまり自信無いです...
typedef struct bucket { ulong h; uint nKeyLength; void *pData; void *pDataPtr; struct bucket *pListNext; struct bucket *pListLast; struct bucket *pNext; struct bucket *pLast; const char *arKey;} Bucket; キー文字列
typedef struct bucket { ulong h; uint nKeyLength; void *pData; void *pDataPtr; struct bucket *pListNext; struct bucket *pListLast; struct bucket *pNext; struct bucket *pLast; const char *arKey;} Bucket; 値まだよく読めてないです...
typedef struct bucket { ulong h; uint nKeyLength; void *pData; void *pDataPtr; struct bucket *pListNext; struct bucket *pListLast; struct bucket *pNext; struct bucket *pLast; const char *arKey;} Bucket;
ハッシュテーブル内の前後の要素
typedef struct bucket { ulong h; uint nKeyLength; void *pData; void *pDataPtr; struct bucket *pListNext; struct bucket *pListLast; struct bucket *pNext; struct bucket *pLast; const char *arKey;} Bucket;
スロット内の前後の要素
二重の双方向リスト
•ハッシュテーブル内のリスト-> 配列の走査に使う
•スロット内のリスト-> ハッシュ値の衝突時に連結
https://www.codeblog.org/blog/moriyoshi/20060824.html
p = ht->pListHead;while (p != NULL) { // p にごにょごにょする p = p->pListNext;}
リスト全体の走査
h = ハッシュ値の計算(arKey, nLength);
// スロット番号の算出nIndex = h & ht->nTableMask;
p = ht->arBuckets[nIndex];while (p != NULL) { if (キーが等しければ) {
*pData = p->pData; return SUCCESS; } p = p->pNext;}return FAILURE;
キーによる探索
PHPにおけるHashDoS
テキスト
http://blog.tokumaru.org/2011/12/webdoshashdos.html
HashDoS とは
•ハッシュ値の衝突する連想配列を作る•Web アプリに入力として与える
•非効率な挿入・検索が起こる•効率よく DoS アタックができる
<?phphashtable_dump(array(0 => 1, 8 => 2, 16 => 3, 24 => 4, 32 => 5, 40 => 6, 48 => 7, 56 => 8));/*nTableSize: 8nTableMask: 7nNumOfElements: 8nNextFreeElement: 57pListHead: 0pListTail: 56**arBuckets: 0 => [56, 48, 40, 32, 24, 16, 8, 0, NULL] 1 => [NULL] 2 => [NULL] 3 => [NULL] 4 => [NULL] 5 => [NULL] 6 => [NULL] 7 => [NULL]*/
全ての要素が同じスロットに
<?phphashtable_dump(array(0 => 1, 8 => 2, 16 => 3, 24 => 4, 32 => 5, 40 => 6, 48 => 7, 56 => 8));/*nTableSize: 8nTableMask: 7nNumOfElements: 8nNextFreeElement: 57pListHead: 0pListTail: 56**arBuckets: 0 => [56, 48, 40, 32, 24, 16, 8, 0, NULL] 1 => [NULL] 2 => [NULL] 3 => [NULL] 4 => [NULL] 5 => [NULL] 6 => [NULL] 7 => [NULL]*/
全ての要素が同じスロットに
非効率な探索
HashDoS への対策•入力による HashTable の生成を制限する (max_input_vars とか)
•根本的解決では無いが, 現実的なリスクを軽減できる
•続きは徳丸さんのブログで
根本的な解決の事例
•Perl (5.8.1 以降)•Ruby (1.8.7-p356 より後)•ハッシュ値の予測を困難にする? まだよく調べてません...
まとめ•PHP の HashTable は HashDoS に対して脆弱である
•運用でカバーしましょう•詳しくは徳丸さんのブログで
ご清聴ありがとうございました
参考資料• アルゴリズムとデータ構造編 第14章 ハッシュ探索①(チェイン法)
http://www.geocities.jp/ky_webid/algorithm/014.html
• PHPソースコードリーディング入門(とっかかり編)http://d.hatena.ne.jp/anatoo/20111031/1319991834
• Webアプリケーションに対する広範なDoS攻撃手法(hashdos)の影響と対策http://blog.tokumaru.org/2011/12/webdoshashdos.html
• Zend_Hash_Del_Key_Or_Index Vulnerabilityhttp://www.hardened-php.net/hphp/zend_hash_del_key_or_index_vulnerability.html
• ハッシュテーブルの実装https://www.codeblog.org/blog/moriyoshi/20060824.html
• PHP のコア: Zend Engine ハッカーの手引きhttp://www.php.net/manual/ja/internals2.php
• PHP Extensions: Understanding and working with hash API Part 1http://zendguru.wordpress.com/2009/05/10/php-extensions-understanding-and-working-with-hash-api-part-1/