Python में AWS WAF कैप्चा कैसे हल करें (405 पेज)

aws waf captcha in python - How to Solve AWS WAF CAPTCHA in Python (405 Pages)

Python में AWS WAF कैप्चा हल करने के लिए आप उस पेज से तीन values पढ़ते हैं जो HTTP 405 से जवाब देता है, और उन्हें CapSkip AWS WAF सॉल्वर को amazon_waf के साथ भेजते हैं, फिर मिले जवाब को aws-waf-token cookie से बदल लेते हैं। यह जवाब कोई ऐसा टोकन नहीं है जिसे आप फ़ॉर्म में पेस्ट कर दें। यह एक voucher जोड़ी है जिसे AWS cookie से बदलता है, इसलिए इस flow में reCAPTCHA से एक चरण ज़्यादा है। यह गाइड CapSkip Python SDK और requests के साथ पूरा loop करीब 70 लाइनों में चलाती है। CapSkip आपके अपने Windows PC पर चलता है और प्रति-हल कोई शुल्क नहीं लगता, इसलिए दोबारा कोशिश करने में कुछ खर्च नहीं होता।

आपको क्या चाहिए

  • CapSkip 3.0.0 या बाद का, जो किसी Windows PC पर चल रहा हो। उस रिलीज़ में AWS WAF हल करने की सुविधा जुड़ी थी। पहली बार शुरू करने के चरण सेटअप गाइड में समझाए गए हैं।
  • Python 3.10 या बाद का और capskip पैकेज का वर्ज़न 1.4.0 या बाद का। वर्ज़न 1.3.0 में amazon_waf method नहीं है। नीचे का कोड Python 3.11.7 और 3.14.0 पर capskip 1.4.0 और requests 2.34.2 के साथ चला। Python 3.10 यहाँ आज़माया नहीं गया।
  • एक PowerShell prompt। कमांड PowerShell syntax में लिखी गई हैं।
  • ऐसा पेज जो आपका अपना हो या जिसे ऑटोमेट करने की आपको अनुमति हो, और जो AWS WAF CAPTCHA action वाले नियम के पीछे हो।
  • सॉल्वर के लिए एक पता। Local मोड में CapSkip केवल उसी डिवाइस के लिए 127.0.0.1 पर जवाब देता है। Server मोड में वह आपके नेटवर्क पते या पब्लिक IP पर सुनता है, ताकि किसी दूसरे PC, VPS या होस्टेड प्लेटफ़ॉर्म पर चल रही script API के ज़रिए उसे कॉल कर सके। दोनों यहाँ सेट किए जाते हैं: कनेक्शन सेटिंग्स.

यह कैसे टेस्ट किया गया: कोड तीन mock सर्वर के सामने चला जो मैंने खुद लिखे थे (यानी टेस्ट के लिए बनाए नकली सर्वर), किसी असली AWS WAF साइट के सामने नहीं। उनमें से एक उन AWS WAF जाँचों की नक़ल करता है जो CapSkip के API दस्तावेज़ में सूचीबद्ध हैं, दूसरा संरक्षित साइट की और तीसरा AWS के token host की भूमिका निभाता है। SDK असली capskip 1.4.0 था। मैंने script को एक बार अपने PC पर चल रहे CapSkip app के सामने भी चलाया, target के रूप में mock साइट के साथ। app नकली पेज को हल नहीं कर सकता, इसलिए उसने तीन बार ERROR_CAPTCHA_UNSOLVABLE लौटाया और script अपने RuntimeError के साथ खत्म हुई, जो दिखाता है कि वह error ApiException के रूप में loop तक पहुँचता है। इसमें कोई असली AWS WAF साइट शामिल नहीं थी, इसलिए नीचे कोई भी संख्या हल का समय नहीं है, और यह नहीं बताया जा सकता कि कोई असली साइट इस flow की बनाई cookie को स्वीकार करेगी।

चरण 1: challenge पेज पढ़ें

जब CAPTCHA action वाला कोई नियम ऐसी रिक्वेस्ट से मेल खाता है जिसमें वैध टोकन नहीं है, तो AWS WAF HTTP 405 और header x-amzn-waf-action को captcha पर सेट करके जवाब देता है। AWS WAF दस्तावेज़ के अनुसार, puzzle वाला पेज तभी शामिल होता है जब रिक्वेस्ट ऐसा Accept header भेजे जो text/html माँगता हो। सादी requests कॉल एक सामान्य Accept भेजती है, इसलिए script खुद एक सेट करती है। उसके बिना आपको ऐसा 405 मिल सकता है जिसमें पढ़ने लायक कुछ नहीं होता।

उस पेज में gokuProps नाम का एक छोटा object होता है जिसमें तीन values हैं: key, iv और context। वह awswaf.com host से challenge.js और captcha.js भी लोड करता है। iv और context values हर challenge पेज के साथ बदलती हैं, इसलिए उन्हें हर बार ताज़ा पढ़ें। header के challenge पर सेट होने वाला 202 response एक अलग चीज़ है: वह AWS WAF का शांत Challenge action है, जिसमें कोई puzzle नहीं होता। CapSkip के दस्तावेज़ सिर्फ़ 405 पेज और विजेट का वर्णन करते हैं, इसलिए यह गाइड उसे कवर नहीं करती।

# pip install capskip requests
import re
import requests

PAGE_URL = "https://www.example.com/"  # the page that answers HTTP 405
HEADERS = {  # AWS WAF sends its puzzle page only when the request accepts HTML
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/130.0 Safari/537.36",
    "Accept": "text/html",
}


def read_challenge(session):
    resp = session.get(PAGE_URL, timeout=30)
    if resp.status_code != 405 or "gokuProps" not in resp.text:
        return None  # no AWS WAF challenge on this response
    block = re.search(r"gokuProps\s*=\s*\{(.*?)\}", resp.text, re.S).group(1)
    field = lambda name: re.search(rf'"{name}"\s*:\s*"([^"]+)"', block).group(1)
    script = lambda name: re.search(rf'<script[^>]+src="([^"]+/{name}\.js)"', resp.text).group(1)
    return {
        "sitekey": field("key"),
        "iv": field("iv"),
        "context": field("context"),
        "challenge_script": script("challenge"),
        "captcha_script": script("captcha"),
    }

जब response CAPTCHA पेज नहीं होता तो function None लौटाती है, ताकि script “हल करने को कुछ नहीं” और “हल हो गया” में फ़र्क़ कर सके। वह values को JSON parser के बजाय दो छोटी regular expressions से पढ़ती है, क्योंकि पेज में JavaScript है, JSON नहीं। अगर आपका target keys को अलग तरह से quote करता है, तो expression बदल दें और कुछ नहीं।

चरण 2: amazon_waf से हल करें

SDK का method amazon_waf है। सिर्फ़ sitekey और url ज़रूरी हैं। challenge पेज के लिए sitekey gokuProps.key है, और iv तथा context बाकी दो values हैं। वे साथ चलती हैं: दोनों भेजें या कोई नहीं। अगर आप दोनों छोड़ देते हैं, तो CapSkip हल के समय उन्हें पेज से पढ़ता है, जिसे दस्तावेज़ ज़्यादा सुरक्षित विकल्प कहते हैं, ख़ासकर जब आपके पेज की कॉपी कुछ मिनट से ज़्यादा पुरानी हो। यह गाइड उन्हें भेजती है क्योंकि उसने पेज अभी कुछ देर पहले ही fetch किया था।

दोनों script पते options हैं। हर पता awswaf.com host पर एक https पता होना चाहिए, और SDK कोई और पता होने पर रिक्वेस्ट भेजने से पहले ही उसे ठुकरा देता है। जवाब एक dictionary के रूप में आता है जिसमें captcha_voucher और existing_token हैं, साथ में कच्चा जवाब code के अंतर्गत और टास्क नंबर captchaId के अंतर्गत। method 300 सेकंड के उस लंबे timeout के साथ इंतज़ार करता है जो reCAPTCHA इस्तेमाल करता है, क्योंकि CapSkip puzzle को असली ब्राउज़र में हल करता है। इसका समय नहीं नापा गया।

from capskip import CapSkip

# Local mode. In Server mode, use your server's address instead.
solver = CapSkip(host="127.0.0.1", port=8080)


def solve(challenge):
    # The answer is a voucher pair, not a token.
    return solver.amazon_waf(
        sitekey=challenge["sitekey"],
        iv=challenge["iv"],
        context=challenge["context"],
        url=PAGE_URL,
        challenge_script=challenge["challenge_script"],
        captcha_script=challenge["captcha_script"],
    )

हल को proxy से भेजने के लिए, call में एक proxy argument जोड़ें: एक dictionary जिसमें type को HTTP पर और uri को user:[email protected]:8080 पर सेट किया गया हो। mock रन में वह in.php पर एक proxy और एक proxytype के रूप में पहुँचा। टेस्ट के लिए एक पता काफ़ी है। AWS WAF के पीछे की साइटें अक्सर CAPTCHA के साथ rate limits भी लगाती हैं, इसलिए एक ही पते से लगातार हल आने पर सख़्त बर्ताव मिलता है, और CapSkip के दस्तावेज़ Settings में एक proxy list या हर call के लिए अलग proxy सुझाते हैं, जब token किसी ख़ास नेटवर्क से आना ज़रूरी हो। CapSkip का अपना सॉल्वर पेज लोड, puzzle और voucher की अदला-बदली, तीनों एक ही proxy से भेजता है, इसलिए AWS को एक ही पता दिखता है। अगर आप हल के साथ proxy देते हैं, तो अपनी रिक्वेस्ट भी उसी से भेजें। इस हिस्से को टेस्ट नहीं किया जा सका। proxies को बदल-बदलकर इस्तेमाल करने का तरीका proxy rotation गाइड में बताया गया है।

चरण 3: voucher को aws-waf-token cookie से बदलें

voucher जोड़ी अकेले किसी काम की नहीं। AWS उसे तैयार cookie से एक voucher endpoint पर बदलता है जो challenge.js के बगल में है: वही folder, बस challenge.js की जगह voucher। जोड़ी को JSON के रूप में POST करें, और जवाब में एक token फ़ील्ड होती है। CapSkip के दस्तावेज़ body को text/plain के रूप में भेजते हैं, साइट से मेल खाते Origin header के साथ। CapSkip app का अपना कोड एक Referer भी भेजता है, इसलिए function दोनों भेजती है। SDK दस्तावेज़ कहते हैं कि जोड़ी थोड़ी ही देर वैध रहती है, इसलिए उसे आते ही बदल लें और कभी स्टोर न करें।

import json
from urllib.parse import urlsplit


def exchange(result, challenge):
    # The voucher endpoint sits beside challenge.js, same folder.
    voucher_url = challenge["challenge_script"].rsplit("/", 1)[0] + "/voucher"
    site = urlsplit(PAGE_URL)
    pair = {
        "captcha_voucher": result["captcha_voucher"],
        "existing_token": result["existing_token"],
    }
    reply = requests.post(
        voucher_url,
        data=json.dumps(pair),
        headers={
            "Content-Type": "text/plain;charset=UTF-8",
            "Origin": f"{site.scheme}://{site.netloc}",
            "Referer": f"{site.scheme}://{site.netloc}/",
        },
        timeout=30,
    )
    reply.raise_for_status()
    return reply.json()["token"]  # the aws-waf-token cookie value

चरण 4: पूरा काम करने वाला उदाहरण

आख़िरी ब्लॉक Python में AWS WAF CAPTCHA का पूरा flow जोड़ता है और retry भी जोड़ता है। चारों ब्लॉक एक के बाद एक एक ही फ़ाइल में सेव करें और चलाएँ। हर कोशिश पेज को दोबारा fetch करती है, इसलिए हर बार नया iv और context साथ जाता है। नाकाम puzzle ApiException उठाता है, और loop नए puzzle के साथ दोबारा कोशिश करता है। टोकन आने के बाद script cookie सेट करके पेज को रिक्वेस्ट करती है।

from capskip import ApiException


def fetch_protected():
    session = requests.Session()
    session.headers.update(HEADERS)
    for attempt in range(1, 4):
        challenge = read_challenge(session)  # fresh page, fresh iv and context
        if challenge is None:
            return session.get(PAGE_URL, timeout=30)  # no challenge, real page
        try:
            result = solve(challenge)
        except ApiException as err:
            print(f"attempt {attempt}: {err}")  # each retry draws a new puzzle
            continue
        token = exchange(result, challenge)  # exchange at once, never store it
        return session.get(PAGE_URL, cookies={"aws-waf-token": token}, timeout=30)
    raise RuntimeError("AWS WAF CAPTCHA not solved in 3 attempts")


if __name__ == "__main__":
    page = fetch_protected()
    print(page.status_code, page.text[:60])

mock रन में script ने दोनों Python वर्ज़न पर इस तरह व्यवहार किया:

mock सेटिंगscript ने क्या किया
हर puzzle का जवाब दिया गयाएक टास्क, voucher की एक अदला-बदली, फिर असली पेज के साथ status 200
पहले दो puzzle ठुकराए गएदो attempt लाइनें, फिर तीसरे टास्क पर status 200
पहले तीन puzzle ठुकराए गएतीन attempt लाइनें, फिर RuntimeError
बिना Accept header की रिक्वेस्टmock ने बिना पेज वाला 405 भेजा, read_challenge ने None लौटाया और script ने 405 प्रिंट किया, इसलिए header रखें

cookie तब तक काम करती है जब तक साइट की immunity time चलती है। AWS डिफ़ॉल्ट रूप से 300 सेकंड रखता है और साइट के मालिक को 60 सेकंड से तीन दिन तक चुनने देता है, जैसा कि AWS WAF दस्तावेज़ में बताया गया है। जब 405 लौटे, तो loop फिर चलाएँ। अगर आप कई रिक्वेस्ट करते हैं, तो हर रिक्वेस्ट पर एक बार हल करने के बजाय टोकन को रखें और तब तक दोबारा इस्तेमाल करें।

आम errors

त्रुटिकारणफिक्स
ValidationExceptioncontext के बिना iv, ऐसा script पता जो awswaf.com host पर https न हो, या ऐसा url जो पूरा पता न होiv और context साथ भेजें, और हर script पता वैसा ही कॉपी करें जैसा पेज में है
ERROR_CAPTCHA_UNSOLVABLE वाला ApiExceptionpuzzle का जवाब नहीं दिया जा सकादोबारा सबमिट करें। जैसा API दस्तावेज़ में लिखा है, हर कोशिश पर नया puzzle आता है
ERROR_TASK_NOT_SUPPORTEDAPI दस्तावेज़ इसे ऐसे task type के लिए सूचीबद्ध करते हैं जो CapSkip में बंद हैCapSkip app में AWS WAF की सेटिंग्स जाँचें
ERROR_PROXY_FORMATproxy string को पार्स नहीं किया जा सकाuser:pass@ip:port इस्तेमाल करें
ERROR_NO_SLOT_AVAILABLEAPI key की request rate limit है और आप उससे आगे निकल गएकुछ सेकंड रुकें और फिर से सबमिट करें
NetworkExceptionCapSkip चल नहीं रहा, या host या port गलत हैCapSkip शुरू करें और कनेक्शन सेटिंग्स जाँचें, फिर यह देखें:
voucher POST ठुकरा दिया गयाज़्यादातर संभावना यही है कि जोड़ी पुरानी है या मेल नहीं खाती। CapSkip app का कोड अमान्य existing_token के लिए AWS से HTTP 400 की उम्मीद करता है। असली AWS के सामने इसे दोहराया नहीं जा सकातुरंत अदला-बदली करें, और नया टास्क सबमिट करें
cookie के साथ भी 405 आ रहा हैटोकन की अवधि खत्म हो गई, या साइट उसे कहीं और से पढ़ती हैफिर से हल करें, और जाँचें कि पेज की अपनी रिक्वेस्ट टोकन को कैसे ले जाती हैं

सॉल्वर को किसी server पर चलाना

script को CapSkip से दो चीज़ें चाहिए: एक host और एक port। Local mode में वह 127.0.0.1 और आपका अपना PC है। Server mode में CapSkip आपके नेटवर्क पते या पब्लिक IP पर सुनता है, ताकि किसी दूसरे PC, VPS या hosted platform पर चल रही script उसी API के ज़रिए उसे कॉल कर सके। CapSkip constructor में host और port बदलें, कोड में और कुछ नहीं बदलता। स्थिर रिमोट एक्सेस के लिए स्टैटिक पब्लिक IP सुझाया जाता है। Server mode फिर भी आपका अपना हार्डवेयर है और फिर भी बिना किसी प्रति-हल शुल्क के है। यह पोर्ट को किसी भी पते के लिए खोल देता है, इसलिए जिन पतों को वहाँ तक नहीं पहुँचना चाहिए उनके लिए Windows Firewall का block rule जोड़ें। mode बदलने का तरीका कनेक्शन सेटिंग्स में दिखाया गया है।

FAQ

क्या Python में बिना ब्राउज़र के AWS WAF CAPTCHA हल किया जा सकता है?

आपकी script को ब्राउज़र की ज़रूरत नहीं। वह CapSkip और साइट को सादी HTTP रिक्वेस्ट भेजती है, और CapSkip उस मशीन पर, जहाँ वह चलता है, puzzle को असली ब्राउज़र में हल करता है, जैसा SDK दस्तावेज़ बताते हैं। 405 status बस वह तरीका है जिससे AWS WAF अपने CAPTCHA action को चिह्नित करता है।

क्या SDK aws-waf-token सीधे लौटाता है?

नहीं। वह captcha_voucher और existing_token लौटाता है, और आप उन्हें voucher endpoint पर टोकन से बदलते हैं। JSON createTask API भी AWS WAF को स्वीकार करती है, और उसके कई formats सीधे टोकन लौटाते हैं। इन formats की सूची API दस्तावेज़ में है।

अगर CAPTCHA किसी फ़ॉर्म के अंदर विजेट हो तो?

यह AWS WAF का इस्तेमाल किया जाने वाला दूसरा रूप है। values gokuProps के बजाय विजेट की apiKey और उसके jsapi.js पते से आती हैं। इसकी पूरी प्रक्रिया Node.js विजेट गाइड में समझाई गई है, और call वही method है।

क्या कोई hosted platform इसे आपके CapSkip के सामने चला सकता है?

हाँ, Server mode के ज़रिए। CapSkip को अपने नेटवर्क या पब्लिक IP पर सुनने के लिए सेट करें, CapSkip constructor को उसी host और port पर पॉइंट करें, और loop वैसे ही काम करता है जैसे एक PC पर। सॉल्वर आपके हार्डवेयर पर ही रहता है।

संक्षेप में

Python में AWS WAF CAPTCHA हल करने में चार काम होते हैं: HTML Accept header के साथ 405 पेज पढ़ें, amazon_waf को call करें, voucher जोड़ी को cookie से बदलें, और cookie के साथ रिक्वेस्ट दोहराएँ। अपनी मशीन पर दोबारा कोशिश मुफ़्त है, और जो साइट कभी-कभी ऐसा puzzle थमा देती है जिसका जवाब नहीं दिया जा सकता, उसके लिए असीमित कैप्चा सॉल्वर का यही मकसद है। SDK की बाकी जानकारी के लिए देखें: Python कैप्चा सॉल्वर पेज.