Web アプリケーションとの対話 (Requests)

サイバーセキュリティBeginner
オンラインで実践に進む

はじめに

「Web アプリケーションとの対話」実験へようこそ。サイバーセキュリティや Web 自動化の世界において、プログラムを通じて Web アプリケーションと対話することは基本的なスキルです。データのスクレイピング、脆弱性のテスト、あるいは反復作業の自動化など、どのような目的であれ、HTTP リクエストを確実に送受信する手段が必要です。

この実験では、強力な Python ライブラリである requests の使い方を学びます。HTTP GET および POST リクエストを送信するスクリプトを作成し、サーバーのレスポンスから重要な情報を抽出したり、フォーム送信を自動化したり、セッションクッキーを管理して認証状態を維持したりする方法を習得します。

生のソケット通信と比較して、requests はより高い抽象度で動作します。ヘッダー、エンコーディング、リダイレクト、クッキーといった HTTP の詳細な処理をライブラリが肩代わりしてくれるため、パケット単位の制御よりも Web の挙動やワークフローを重視するセキュリティ自動化の用途に最適です。

HTTP GET リクエストの送信

このステップでは、Python を使用して基本的な HTTP GET リクエストを送信する方法を学びます。GET メソッドは、ブラウザに URL を入力して Web ページをリクエストするのと同様に、指定されたリソースからデータを取得するために使用されます。

これは Web 自動化の最も単純な形式であり、リソースを要求してその応答を検査するものです。多くの偵察、テスト、監視タスクはここから始まります。

まず、プロジェクトディレクトリにいることを確認してください。この実験で作成するすべての Python スクリプトはここに保存します。

cd ~/project

次に、あらかじめ用意されたローカル Web サーバーに対して GET リクエストを送信する Python スクリプトを作成します。nano テキストエディタを使用して get_request.py という名前のファイルを作成します。

nano get_request.py

エディタに以下の Python コードを入力します。

import requests

url = 'http://127.0.0.1:5000/get'
response = requests.get(url)

print("Response Body:")
print(response.text)

ファイルを保存してエディタを終了します(nano の場合、Ctrl+O、Enter で保存し、Ctrl+X で終了します)。

上記のコードは requests ライブラリをインポートし、ターゲットの URL を定義して、requests.get() 関数でリクエストを送信しています。サーバーからの応答は response 変数に格納され、応答本文の生のテキストを出力します。

Python インタプリタを使用してスクリプトを実行します。

python3 get_request.py

以下のような出力が表示されるはずです。

Response Body:
{"message":"GET request successful"}

HTTP ステータスとヘッダーの抽出

このステップでは、HTTP レスポンスからより詳細な情報、具体的にはステータスコードとヘッダーを抽出する方法を学びます。

レスポンス本文は情報の一部に過ぎません。ステータスコードはサーバーがリクエストをどのように理解したかを示し、ヘッダーはコンテンツタイプ、キャッシュポリシー、クッキー、サーバーソフトウェアなどのメタデータを記述します。優れた自動化ツールは、コード、ヘッダー、本文の 3 つの層すべてを確認します。

サーバーが HTTP リクエストに応答する際、ステータスコード(OK なら 200、見つからない場合は 404 など)と、応答に関するメタデータを提供するヘッダーが含まれます。

プロジェクトディレクトリに check_status.py という新しいファイルを作成します。

nano check_status.py

以下のコードをファイルに追加します。

import requests

url = 'http://127.0.0.1:5000/get'
response = requests.get(url)

print(f"Status Code: {response.status_code}")

if response.status_code == 200:
    print("The request was successful!")

print("\nResponse Headers:")
print(f"Content-Type: {response.headers.get('Content-Type')}")
print(f"Server: {response.headers.get('Server')}")

ファイルを保存してエディタを終了します。

このスクリプトでは、response.status_code でサーバーから返された整数型のステータスコードを取得しています。response.headers は、サーバーから返されたすべての HTTP ヘッダーを含む辞書のようなオブジェクトです。.get() メソッドを使用することで、特定のヘッダーを安全に抽出できます。

スクリプトを実行して、抽出された情報を確認します。

python3 check_status.py

出力は以下のようになります。

Status Code: 200
The request was successful!

Response Headers:
Content-Type: application/json
Server: Werkzeug/3.0.1 Python/3.10.12

フォーム送信の自動化 (POST)

このステップでは、HTTP POST リクエストを送信する方法を学びます。データを取得するために使用される GET リクエストとは異なり、POST リクエストはサーバーにデータを送信するために使用されます。これは、ログイン認証情報などの Web フォームを送信する際によく使われます。

この区別は HTTP のセマンティクスを反映しています。実際には、GET はリソースの読み取りに使用され、POST は送信や状態変更を伴うアクションに使用されるのが一般的です。この違いを理解することで、アプリケーションの挙動を予測し、スクリプトがどのように対話すべきかを判断できるようになります。

ここでは、ユーザー名とパスワードを使用してログインフォームを送信するシミュレーションを行うスクリプトを作成します。

post_request.py という新しいファイルを作成します。

nano post_request.py

以下のコードを入力します。

import requests

url = 'http://127.0.0.1:5000/post'

## フォームデータを辞書として定義
form_data = {
    'username': 'admin',
    'password': 'secret'
}

## data パラメータを指定して POST リクエストを送信
response = requests.post(url, data=form_data)

print(f"Status Code: {response.status_code}")
print(f"Response Body: {response.text}")

ファイルを保存してエディタを終了します。

ここでは、認証情報を含む form_data という辞書を定義しています。次に requests.post() を使用し、data パラメータにこの辞書を渡します。requests ライブラリは、このデータを標準的な Web フォーム送信の形式に自動的に変換します。

スクリプトを実行してフォームを送信します。

python3 post_request.py

ログイン成功のメッセージが表示されるはずです。

Status Code: 200
Response Body: {"message":"Login successful"}

スクリプト内のパスワードを誤った値(wrongpass など)に変更して再度実行し、サーバーが 401 Unauthorized ステータスコードで応答する様子を確認してみることもできます。

セッションクッキーの管理

最後のステップでは、セッションクッキーを管理する方法を学びます。HTTP はステートレスなプロトコルであり、各リクエストは独立しています。ユーザーがログインした後にその状態を記憶するために、Web アプリケーションはクッキーを使用します。

requests.get() や requests.post() を直接使用する場合、リクエスト間でクッキーは保存されません。セッションを維持(ログイン状態を保持)するには、requests ライブラリが提供する Session オブジェクトを使用する必要があります。

session_request.py というファイルを作成します。

nano session_request.py

以下のコードを追加します。

import requests

## Session オブジェクトを作成
session = requests.Session()

login_url = 'http://127.0.0.1:5000/login'
profile_url = 'http://127.0.0.1:5000/profile'

print("Attempting to access profile BEFORE login...")
response1 = session.get(profile_url)
print(f"Status: {response1.status_code}, Body: {response1.text.strip()}")

print("\nLogging in to establish a session...")
## セッションオブジェクトはサーバーから返されたクッキーを自動的に保存します
session.post(login_url)

print("\nAttempting to access profile AFTER login...")
## セッションオブジェクトはこのリクエストで保存されたクッキーを自動的に送信します
response2 = session.get(profile_url)
print(f"Status: {response2.status_code}, Body: {response2.text.strip()}")

ファイルを保存してエディタを終了します。

このスクリプトでは、requests.Session() が永続的なセッションを作成します。/login に対して POST リクエストを送信すると、サーバーがセッションクッキーを設定します。Session オブジェクトはこのクッキーを保存し、その後の /profile への GET リクエストに自動的に含めるため、保護されたルートにアクセスできるようになります。

スクリプトを実行します。

python3 session_request.py

出力を確認してください。最初のアクセスはログインしていないため失敗しますが、2 回目のアクセスはセッションクッキーが自動的に管理されるため成功することがわかります。

Attempting to access profile BEFORE login...
Status: 401, Body: {"message":"Unauthorized"}

Logging in to establish a session...

Attempting to access profile AFTER login...
Status: 200, Body: {"message":"Welcome to your profile!"}

まとめ

Python の requests ライブラリを使用して Web インタラクションを自動化する方法を学びました。基本的な HTTP GET リクエストの送信と、ステータスコードやヘッダーといった重要なメタデータの抽出から始め、HTTP POST リクエストによるフォーム送信の自動化へと進みました。最後に、Session オブジェクトを使用してクッキーを管理し、複数のリクエストにわたって認証状態を維持する方法を習得しました。

これらのスキルは、Web スクレイピング、API 統合、自動化されたセキュリティテストなど、多くの高度なタスクの基礎となります。