ラベル security の投稿を表示しています。 すべての投稿を表示
ラベル security の投稿を表示しています。 すべての投稿を表示

2011年9月17日土曜日

Apache 2.2.21 リリース

Apacheの脆弱性(CVE-2011-3192)に対応した 2.2.20 からまもなく 2.2.21 がリリースされています。 2.2.20 で行った修正に対する改善や、新たにMaxRangesディレクティブの追加などが含まれている模様。 

そもそも問題となっている Range ヘッダは、ブラウザでPDFの閲覧をしている時などにも使用されています。
GET /net/apache//httpd/docs/httpd-docs-2.2.14.en.pdf HTTP/1.1
Accept: */*
Range: bytes=3653554-3854257, 1077245-3603942, 3608039-3653553
...

このヘッダを使用して、なぜプロセスの肥大化が引き起こされるのかについては下記のページで丁寧に説明されていて、Range で細かい区間を要求されることにより、管理データを追加していくループ処理の増加が原因とのこと。

  CVE-2011-3192 Range header DoS vulnerability Apache 1.3/2.x の更に続き

追加された MaxRanges ディレクティブ では、制限値(デフォルト: 200)を超えた場合、要求されたコンテンツをそのまま返すようになっています。区間要求が無視されることにより、プロセスの肥大化を防ぐ仕組みですね。
# vi httpd.conf
----------------------
# MaxRanges: Maximum number of Ranges in a request before
# returning the entire resource, or 0 for unlimited
# Default setting is to accept 200 Ranges
MaxRanges 5
----------------------

// 制限内の数を指定した場合
GET / HTTP/1.1
Host: localhost
Range: bytes=0-1,1-2,2-3,3-4,4-5 <= 一度に複数の範囲を指定

HTTP/1.1 206 Partial Content <= 206 レスポンスが返る
...
Accept-Ranges: bytes
Content-Length: 412
Content-Type: multipart/byteranges; boundary=4ad1ca44eeaa22

// 制限を超過した場合
GET / HTTP/1.1
Host: localhost
Range: bytes=0-1,1-2,2-3,3-4,4-5,5-6

HTTP/1.1 200 OK <= 要求されたコンテンツをそのまま返している
...
Accept-Ranges: bytes
Content-Length: 44
Content-Type: text/html

2011年6月1日水曜日

Python の hash関数

Google Code University に Gruyere というデモサイトを使って、Webアプリケーションの脆弱性と対策を説明しているガイドがあります。

少しずつ読み進めているのですが、cookie処理の部分について少し調べてみました。

gruyere.py (601行目)
def _CreateCookie(self, cookie_name, uid):
    ....
    h_data = str(hash(cookie_secret + c_data) & 0x7FFFFFF)

発行するcookieにハッシュ値を付与している部分ですが、「Pythonのhash関数はセキュアでないため、"違う文字列で同じハッシュ値" を短い時間で発見できる」と説明されています。

そうすると cookie_secret を知らなくても、cookieの改ざんができてしまうため、この用途にhash関数は向いていないとのこと。対策として「セキュアなhash関数を使用する」とあるので、hashlib などを使用するべきなのかな。

そもそも、Pythonのhash関数は dict での使用に適するようにされていて、ランダムよりも(末尾の文字がインクリメントされるような)よく似たケースにおいて規則的な変化をする性質を重視していると dictobject.c のコメントに書かれているんですね。

python/Objects/dictobject.c
/*
Major subtleties ahead:  Most hash schemes depend on
having a "good" hash function, in the sense of simulating
randomness.  Python doesn't:  its most important hash
functions (for strings and ints) are very regular in
common cases:
'''
>>> map(hash, (0, 1, 2, 3))
[0, 1, 2, 3]
>>> map(hash, ("namea", "nameb", "namec", "named"))
[-1658398457, -1658398460, -1658398459, -1658398462]

また、Pythonのhash関数はFNVというアルゴリズムに近いものだそうだ。

FNV-1 hash algorithm
hash = FNV_offset_basis
for each octet_of_data to be hashed
    hash = hash  FNV_prime
    hash = hash XOR octet_of_data

python/Objects/stringobject.c
string_hash(PyStringObject *a)
{
    ...
    x = *p << 7;
    while (--len >= 0)
        x = (1000003*x) ^ *p++;

この辺りがそうなのかな。
きちんと理解できるように、がんばらねば。