
Requestsを使ってWebアプリのレースコンディションを簡単に悪用できるようにする小さなPythonライブラリ。
Requests-Racer は、Requests ライブラリを使用して、宛先が異なる場合やペイロードのサイズが異なる場合でも、複数のリクエストをそれらの宛先サーバーでほぼ同時に処理されるように送信できる小さな Python ライブラリです。これは、Web アプリケーションにおける競合状態の脆弱性を検出および悪用するのに役立ちます。(詳細については、motivation.md を参照してください。)
Requests (および Requests が内部で使用する urllib3) は、そもそもこのようなことを想定して設計されたものではありません。そのため、Requests-Racer は、リクエストの送信方法を細かく制御するために、かなりひどいハックに頼らざるを得ません。
これらのハックには、一部の urllib3 オブジェクトのプライベート状態をいじることが含まれるため、公開 API に関して後方互換性のある urllib3 のアップデートでも Requests-Racer を壊す可能性があります。したがって、Requests-Racer は virtualenv 内で使用し、Requests または urllib3 より前にインストールして、これらのライブラリの既知の互換性のあるバージョンが依存関係として取り込まれるようにすることをお勧めします。
Requests-Racer を使用するには、Python 3.5 以降が必要です。まず、Python 仮想環境を作成して有効化します:
python3 -m venv env
source env/bin/activate
次に、ライブラリのコピーをダウンロードしてインストールします:
git clone https://github.com/nccgroup/requests-racer.git
cd requests-racer
python setup.py install
Requests-Racer は、SynchronizedAdapter と呼ばれる Requests 用の代替 トランスポートアダプター を提供することで機能します。このアダプターは、そのアダプターを通じて行われたすべてのリクエストを収集し、finish_all() メソッドが呼び出されたときにのみそれらを完了させます:
import requests
from requests_racer import SynchronizedAdapter
s = requests.Session()
sync = SynchronizedAdapter()
s.mount('http://', sync)
s.mount('https://', sync)
resp1 = s.get('http://example.com/a', params={'hello': 'world'})
resp2 = s.post('https://example.net/b', data={'one': 'two'})
# at this point, the requests have been started but not finished.
# resp1 and resp2 should *not* be used.
sync.finish_all()
print(resp1.status_code)
print(resp2.text)
コードをよりシンプルにするには、SynchronizedSession を使用することもできます。これは、HTTP[S] 用に SynchronizedAdapter を自動的にマウントし、finish_all() メソッドをプロキシする requests.Session オブジェクトにすぎないため、上記のコードは次のように書き換えることができます:
from requests_racer import SynchronizedSession
s = SynchronizedSession()
resp1 = s.get('http://example.com/a', params={'hello': 'world'})
resp2 = s.post('https://example.net/b', data={'one': 'two'})
# at this point, the requests have been started but not finished.
# resp1 and resp2 should *not* be used.
s.finish_all()
print(resp1.status_code)
print(resp2.text)
以下に、留意すべき注意点と、実行できるより高度なことを示します:
SynchronizedAdapter はスレッドセーフではありません。
SynchronizedAdapter を通じて行われたリクエストは、セッションオブジェクトを更新しません(例: Set-Cookie ヘッダーの Cookie はセッションの Cookie ジャーに追加されません)。
リダイレクトは追跡されない可能性があるため、避けるようにしてください。
リクエストの開始中に例外が発生した場合、その例外は通常のリクエストとまったく同様に再送出されます。ただし、リクエストの完了中に例外が発生した場合は、再送出されません。代わりに、そのリクエストのレスポンスはステータスコード 999 になり、.text 属性にトレースバックが含まれます。
SynchronizedSession.from_regular_session は、requests.Session インスタンスから SynchronizedSession を構築します。これは、例えばサービスにログインして同期リクエストに必要なセッション Cookie を取得するといった、簡単なリクエストを行う必要がある場合に役立ちます。
SynchronizedAdapter と SynchronizedSession は、num_threads というオプションのパラメータを受け入れます。これは、アダプターが使用するスレッドの最大数を指定します。指定しない場合、アダプターはリクエストごとに 1 つのスレッドを使用します。
パフォーマンスに関するメモについては、benchmark/ を参照してください。
Copyright (C) 2019 Aleksejs Popovs, NCC Group
このプログラムは自由ソフトウェアです。あなたはこれを、フリーソフトウェア財団によって発行された GNU 一般公衆利用許諾書(バージョン 3 か、それ以降のバージョンのうちどれか)の定める条件の下で再頒布し、および/または改変することができます。
このプログラムは有用であることを願って頒布されますが、一切の保証はありません。商品性または特定目的への適合性についての暗黙の保証もありません。詳細は GNU 一般公衆利用許諾書をご覧ください。
あなたはこのプログラムと共に、GNU 一般公衆利用許諾書の写しを受け取っているはずです。受け取っていない場合は、https://www.gnu.org/licenses/ をご覧ください。
finish_all() は、timeout というオプションのパラメータを受け入れます。これは、アダプターがスレッドの終了を待機する最大時間(秒)を指定します。