HashTable
       と
HashDoS
  @yuya_takeyama
For
   the
Beginners
By
    a
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;
ドユコト?
可視化
しましょう 
<?php
hashtable_dump(array(1, 2, 3, 4, 5, 6, 7, 8));
/*
nTableSize:       8
nTableMask:       7
nNumOfElements:   8
nNextFreeElement: 8
pListHead:        0
pListTail:        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]
                            スロット数
<?php
hashtable_dump(array(1, 2, 3, 4, 5, 6, 7, 8));
/*
nTableSize:       8
nTableMask:       7
nNumOfElements:   8
nNextFreeElement: 8
pListHead:        0
pListTail:        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]
                                        要素数
<?php
hashtable_dump(array(1, 2, 3, 4, 5, 6, 7, 8));
/*
nTableSize:       8
nTableMask:       7
nNumOfElements:   8
nNextFreeElement: 8
pListHead:        0
pListTail:        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]
                            末尾の要素
<?php
hashtable_dump(array(1, 2, 3, 4, 5, 6, 7, 8));
/*
nTableSize:       8
nTableMask:       7
nNumOfElements:   8
nNextFreeElement: 8
pListHead:        0
pListTail:        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 アタックができる
<?php
hashtable_dump(array(0 => 1, 8 => 2, 16 => 3, 24 => 4,
                      32 => 5, 40 => 6, 48 => 7, 56 => 8));
/*
nTableSize:        8
nTableMask:        7
nNumOfElements:    8
nNextFreeElement: 57
pListHead:         0
pListTail:         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]
                    同じスロットに
<?php
hashtable_dump(array(0 => 1, 8 => 2, 16 => 3, 24 => 4,




  非効率な
                      32 => 5, 40 => 6, 48 => 7, 56 => 8));
/*
nTableSize:        8
nTableMask:        7
nNumOfElements:    8
nNextFreeElement: 57
pListHead:         0
pListTail:         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 Vulnerability
    http://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 1
    http://zendguru.wordpress.com/2009/05/10/php-extensions-
    understanding-and-working-with-hash-api-part-1/

HashTable と HashDos

  • 1.
    HashTable と HashDoS @yuya_takeyama
  • 2.
    For the Beginners
  • 3.
    By a Beginner
  • 4.
  • 5.
    ハッシュテーブルとは •Key から Valueを検索 • 連想配列に使われる • 基本的には効率的で高速 • 最悪の場合はとても非効率に
  • 6.
  • 7.
    PHP における ハッシュテーブル •HashTable 構造体 • 複数の Bucket 構造体から成る • 順番を保持
  • 8.
    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;
  • 9.
    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; スロット数
  • 10.
    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; 要素数
  • 11.
    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; 末尾の要素
  • 12.
    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;
  • 13.
  • 14.
  • 17.
    <?php hashtable_dump(array(1, 2, 3,4, 5, 6, 7, 8)); /* nTableSize: 8 nTableMask: 7 nNumOfElements: 8 nNextFreeElement: 8 pListHead: 0 pListTail: 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] スロット数
  • 18.
    <?php hashtable_dump(array(1, 2, 3,4, 5, 6, 7, 8)); /* nTableSize: 8 nTableMask: 7 nNumOfElements: 8 nNextFreeElement: 8 pListHead: 0 pListTail: 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] 要素数
  • 19.
    <?php hashtable_dump(array(1, 2, 3,4, 5, 6, 7, 8)); /* nTableSize: 8 nTableMask: 7 nNumOfElements: 8 nNextFreeElement: 8 pListHead: 0 pListTail: 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] 末尾の要素
  • 20.
    <?php hashtable_dump(array(1, 2, 3,4, 5, 6, 7, 8)); /* nTableSize: 8 nTableMask: 7 nNumOfElements: 8 nNextFreeElement: 8 pListHead: 0 pListTail: 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] 集まり
  • 21.
  • 22.
    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; ここあんまり自信無いです... ハッシュ値
  • 23.
    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; キー文字列
  • 24.
    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; まだよく読めてないです... 値
  • 25.
    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; 前後の要素
  • 26.
    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; 前後の要素
  • 27.
  • 28.
  • 29.
    p = ht->pListHead; while(p != NULL) { // p にごにょごにょする p = p->pListNext; } リスト全体の 走査
  • 30.
    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; よる探索
  • 31.
  • 32.
  • 33.
    HashDoS とは •ハッシュ値の衝突する連想配列を作る • Webアプリに入力として与える •非効率な挿入・検索が起こる •効率よく DoS アタックができる
  • 34.
    <?php hashtable_dump(array(0 => 1,8 => 2, 16 => 3, 24 => 4, 32 => 5, 40 => 6, 48 => 7, 56 => 8)); /* nTableSize: 8 nTableMask: 7 nNumOfElements: 8 nNextFreeElement: 57 pListHead: 0 pListTail: 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] 同じスロットに
  • 35.
    <?php hashtable_dump(array(0 => 1,8 => 2, 16 => 3, 24 => 4, 非効率な 32 => 5, 40 => 6, 48 => 7, 56 => 8)); /* nTableSize: 8 nTableMask: 7 nNumOfElements: 8 nNextFreeElement: 57 pListHead: 0 pListTail: 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]
  • 36.
    HashDoS への対策 • 入力による HashTableの生 成を制限する (max_input_vars とか) • 根本的解決では無いが, 現実的 なリスクを軽減できる • 続きは徳丸さんのブログで
  • 37.
    根本的な解決の事例 •Perl (5.8.1 以降) • Ruby (1.8.7-p356 より後) • ハッシュ値の予測を困難にす る? まだよく調べてません...
  • 38.
    まとめ • PHP の HashTableは HashDoS に対して脆弱であ る • 運用でカバーしましょう • 詳しくは徳丸さんのブログで
  • 39.
  • 40.
    参考資料 • アルゴリズムとデータ構造編 第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 Vulnerability http://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 1 http://zendguru.wordpress.com/2009/05/10/php-extensions- understanding-and-working-with-hash-api-part-1/