解答済みトークンの送信時にアプリケーションのCookieを維持する

著者:solvethree読了時間:1分

解決済みのreCAPTCHAトークンは、アプリケーションのセッションCookieやCSRF値の代わりにはなりません。同じrequests.Sessionでフォームを取得して送信し、GETで受け取ったCookieがPOSTでも維持されるようにしてください。

アプリケーションへの両方のリクエストで、ソルバーが返したブラウザーヘッダーと同じプロキシを使ってください。この例では、フォームを開く前にヘッダーを利用できるよう、先に解決を行います。

このページの内容

フォームのGETとPOSTを同じセッションで行う

requestsと公式のsolvethree Python SDKをインストールしたPython 3.10+を使用してください。対象ホスト名には、ワークスペース内で有効なプロファイルが必要です。タスクにホスト名を指定しても、プロファイルは作成されません。未設定の場合は、サイトプロファイルの設定を参照してください。

  • TARGET_URLにアプリケーションのフォームURLを設定してください。この所有下のデモでは、GETとPOSTに同じURLを使います。
  • SOLVETHREE_PROXYに、解決処理とアプリケーションへの両方のリクエストで使う単一のプロキシを設定してください。
  • SOLVETHREE_API_KEYにワークスペースのAPIキーを設定してください。このコードはサーバー側で実行してください。
requests.Session · アプリケーションのCookieとCSRF値を保持
# This owned demo form has an input named csrf_token and g-recaptcha-response.
import os
from html.parser import HTMLParser
from urllib.parse import urlsplit
import requests
from solvethree import Solvethree

class FormParser(HTMLParser):
    csrf = None
    def handle_starttag(self, tag, attributes):
        values = dict(attributes)
        if tag == "input" and values.get("name") == "csrf_token":
            self.csrf = values.get("value")

target = os.environ["TARGET_URL"]
proxy = os.environ["SOLVETHREE_PROXY"]
request = {"site": urlsplit(target).hostname, "action": "login", "proxy": proxy}
# Obtain the solver's browser headers before opening the application session.
result = Solvethree(os.environ["SOLVETHREE_API_KEY"]).solve(request, timeout=180)
solution = result["solution"]
with requests.Session() as session:
    session.headers.update({"User-Agent": solution["userAgent"], "sec-ch-ua": solution["secChUa"]})
    proxies = {"http": proxy, "https": proxy}
    page = session.get(target, proxies=proxies, timeout=20, allow_redirects=False)
    page.raise_for_status()
    parser = FormParser(); parser.feed(page.text)
    if not parser.csrf: raise RuntimeError("The expected demo CSRF input was not found")
    response = session.post(target, proxies=proxies, timeout=20, allow_redirects=False,
        data={"csrf_token": parser.csrf, "g-recaptcha-response": solution["token"]})
    print("Application HTTP status:", response.status_code)
    # Use the actual form's submit URL, fields and session rules. Inspect its result.

SDKのsolve呼び出しはタスクを作成し、準備完了になるか例外が発生するまでポーリングします。その後、この例ではsolution.userAgentとsolution.secChUaをセッションに適用します。GETでCookie jarにCookieが格納され、POSTではそのCookie jarを再利用し、フォームから解析したCSRF値とともにsolution.tokenを送信します。

デモのloginアクション、送信URL、フォームフィールドをアプリケーションに合わせて変更してください。csrf_tokenはこのフォームのフィールド名であり、solvethreeの要件ではありません。別の名前や構造を使っている場合はHTMLパーサーを調整し、ログイン認証情報など、ほかの必須フィールドも含めてください。送信URLがフォームURLと異なる場合も、同じセッションを使ってください。

アプリケーションがPOSTを拒否した場合

出力されたHTTPステータスは調査の出発点であり、ログイン成功の証拠ではありません。次の解決処理に料金を支払う前に、アプリケーションのレスポンスと送信リクエストを確認してください。タスクが準備完了であることは、解決結果が生成されたことを意味します。送信を受け入れるかどうかは、引き続きアプリケーションが判断します。

CSRFの入力要素が見つからない。

GETレスポンスのステータスと本文を確認してください。リダイレクトの追跡は無効なので、リダイレクトレスポンスは期待するフォームではありません。

試してみましょう: 同じセッションで正しいフォームを明示的に取得し、実際のCSRFフィールドに合わせてパーサーを調整してください。

アプリケーションがセッションの欠落またはCSRF値の無効を報告する。

GETでCookieを受信したか、POSTで適用対象のCookieを送信したか、CSRF値がそのフォームのレスポンスから取得されたものかを確認してください。

試してみましょう: 両方のリクエストで同じrequests.Sessionを使ってください。あるクライアントでフォームを取得し、別のクライアントで送信しないでください。

アプリケーションがCAPTCHAを拒否する。

送信するトークンフィールド、アクション、プロキシ、User-Agent、sec-ch-uaを確認してください。タスクIDや古いトークンではなく、solution.tokenを送信していることを確認してください。

試してみましょう: 現在のトークン、解決時と同じプロキシ、返されたブラウザーヘッダーを使ってください。トークンの有効期限が切れた、またはすでに評価済みの場合は、送信に近いタイミングで新しいトークンを取得してください。

POSTは完了するが、ログインできない。

レスポンス本文とリダイレクト先に加え、実際の送信URLと必須フォームフィールドを確認してください。

試してみましょう: デモのフォームデータをアプリケーションの仕様に合わせて調整してください。CAPTCHAトークンは、認証情報や不足しているほかのアプリケーションフィールドを補うものではありません。

最初のタスクを実行しましょう。

$5のワークスペースクレジットで始められます。

ワークスペースを作成
解答済みトークンの送信時にアプリケーションのCookieを維持する · solvethree