Node.js से AWS WAF विजेट कैप्चा कैसे हल करें

aws waf captcha in node.js - How to Solve an AWS WAF Widget CAPTCHA With Node.js

किसी विजेट पेज पर Node.js में AWS WAF CAPTCHA हल करने के लिए आप पेज से विजेट की apiKey और jsapi.js का पता पढ़ते हैं, और उन्हें CapSkip AWS WAF सॉल्वर को amazonWaf के साथ भेजते हैं, लौटी हुई voucher जोड़ी को टोकन से बदलते हैं, और वह टोकन अपनी अगली रिक्वेस्ट के साथ भेजते हैं। विजेट AWS WAF का इस्तेमाल किया जाने वाला दूसरा रूप है। कोई फ़ॉर्म या लॉगिन पेज खुद puzzle बनाता है, इसलिए न कोई HTTP 405 पेज है और न पढ़ने के लिए gokuProps। यह गाइड पूरा loop CapSkip Node.js SDK और Node.js के साथ आने वाले fetch से करती है। 405 पेज के बारे में पढ़ने के लिए देखें: Python गाइड.

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

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

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

चरण 1: प्रोजेक्ट सेट करें और विजेट की values खोजें

एक folder बनाएँ, एक प्रोजेक्ट शुरू करें और capskip इंस्टॉल करें:

npm init -y
npm install capskip

विजेट पेज jsapi.js नाम की एक script लोड करता है और एक options object के साथ AwsWafCaptcha.renderCaptcha को call करता है। AWS WAF दस्तावेज़ के अनुसार, उस object की apiKey एक एन्क्रिप्टेड key है जिसमें विजेट इस्तेमाल कर सकने वाले client domains की सूची होती है, इसलिए वह एक ही साइट की होती है। CapSkip को पेज से दो चीज़ें चाहिए: वही apiKey, जिसे वह sitekey कहता है, और jsapi.js का पूरा पता। विजेट पेज में gokuProps नहीं होता, इसलिए आप न iv भेजते हैं और न context। इनके बिना jsapi.js का पता भेजना ही रिक्वेस्ट को विजेट हल के रूप में चिह्नित करता है।

पहला ब्लॉक दोनों को पेज के HTML से पढ़ता है। कुछ साइटें apiKey को इसके बजाय अलग JavaScript bundle में रखती हैं। ऐसा होने पर function null लौटाती है, और हल यह है कि पेज जो scripts लोड करता है उनमें apiKey खोजें।

'use strict';
const { CapSkip, ApiException } = require('capskip');

const PAGE_URL = 'https://www.example.com/contact'; // the page that draws the widget
// The folder that the page's challenge.js loads from (see the Network tab).
const TOKEN_BASE = 'https://3f2a9c7d41b0.edge.sdk.awswaf.com/3f2a9c7d41b0/8e51d0c7a2f4/';

async function readWidget() {
  const res = await fetch(PAGE_URL, { headers: { Accept: 'text/html' } });
  const html = await res.text();
  const src = /<script[^>]+src="([^"]*\/jsapi\.js)"/i.exec(html);
  const key = /apiKey\s*:\s*["']([^"']+)["']/.exec(html);
  if (!src || !key) return null; // not in the HTML: look in the page's scripts
  return { sitekey: key[1], jsapiScript: new URL(src[1], PAGE_URL).href };
}

पेज पर script का पता relative हो सकता है या दो slash से शुरू हो सकता है, इसलिए function उसे पेज के URL की मदद से पूरे पते में बदल देती है। ब्लॉक में सबसे ऊपर TOKEN_BASE एक constant है जिसे आप हाथ से भरते हैं, और अगला चरण बताता है क्यों।

चरण 2: token host एक बार खोजें

voucher जोड़ी को AWS के अपने host पर टोकन से बदला जाता है। विजेट पेज पर वह host आपके fetch किए HTML में नहीं होता। पेज को ब्राउज़र में खोलें, Network tab खोलें, reload करें, और challenge.js की वह रिक्वेस्ट खोजें जो jsapi.js आपके लिए करता है। उसका folder वही है जिसे कॉपी करना है, अंत में slash के साथ। CapSkip के दस्तावेज़ कहते हैं कि challenge.js की जगह voucher रखें, जो अगले चरण का कोड TOKEN_BASE के साथ करता है।

यह हर साइट के लिए एक बार की खोज है, इसलिए इसे अपनी configuration में रखें। असली साइट पर यह कितने समय तक वैसा ही रहता है, यह नहीं बताया जा सकता। अगर अगले चरण की अदला-बदली नाकाम होने लगे, तो किसी और चीज़ पर शक करने से पहले Network tab दोबारा जाँचें।

चरण 3: हल करें और voucher बदलें

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

अदला-बदली voucher endpoint पर एक POST है, जिसमें जोड़ी JSON body के रूप में जाती है। CapSkip के दस्तावेज़ इसे साइट से मेल खाते Origin header के साथ text/plain के रूप में भेजते हैं। CapSkip app का अपना कोड एक Referer भी भेजता है, इसलिए कोड दोनों भेजता है। Node.js का fetch आपको Origin सेट करने देता है, जो ब्राउज़र नहीं करने देता। SDK दस्तावेज़ कहते हैं कि जोड़ी थोड़ी ही देर वैध रहती है, इसलिए उसे तुरंत बदलें और कभी स्टोर न करें।

// Local mode. In Server mode, use your server's address instead.
const solver = new CapSkip({ host: '127.0.0.1', port: 8080 });

async function getToken(widget) {
  // The answer is a voucher pair, not a token.
  const result = await solver.amazonWaf(widget.sitekey, PAGE_URL, {
    jsapiScript: widget.jsapiScript,
  });
  const reply = await fetch(new URL('voucher', TOKEN_BASE), {
    method: 'POST',
    headers: {
      'Content-Type': 'text/plain;charset=UTF-8',
      Origin: new URL(PAGE_URL).origin,
      Referer: new URL(PAGE_URL).origin + '/',
    },
    body: JSON.stringify({
      captcha_voucher: result.captcha_voucher,
      existing_token: result.existing_token,
    }),
  });
  if (!reply.ok) throw new Error(`voucher exchange failed: HTTP ${reply.status}`);
  return (await reply.json()).token; // the aws-waf-token value
}

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

चरण 4: टोकन उसी तरह भेजें जैसे पेज भेजता है

विजेट पेज पर टोकन वही है जो पेज के अपने onSuccess callback को मिलता है। पेज उसे आगे कैसे देते हैं, इसमें फ़र्क़ होता है। कई उसे aws-waf-token cookie के रूप में भेजते हैं और बाकी x-aws-waf-token header के रूप में, इसलिए Network tab खोलकर फ़ॉर्म एक बार हाथ से सबमिट करें और वही कॉपी करें जो पेज की रिक्वेस्ट ले जाती है। नीचे की function cookie भेजती है और header को विकल्प के रूप में दिखाती है। फ़ॉर्म के fields placeholder हैं, आप अपने fields रखें।

function submitForm(token) {
  return fetch(PAGE_URL, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      Cookie: `aws-waf-token=${token}`, // or 'x-aws-waf-token': token
    },
    body: new URLSearchParams({ email: '[email protected]', message: 'Hello' }),
  });
}

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

आख़िरी ब्लॉक सारे हिस्सों को retry और entry point के साथ Node.js में एक पूरे AWS WAF CAPTCHA सॉल्वर में बदलता है। चारों code ब्लॉक एक के बाद एक एक ही फ़ाइल में सेव करें और node से चलाएँ। नाकाम puzzle ApiException उठाता है, और loop दोबारा कोशिश करता है, जिससे हर बार नया puzzle आता है। कोई भी और error throw हो जाती है, इसलिए गलत host या ठुकराई गई अदला-बदली चुपचाप दोबारा नहीं आज़माई जाती।

async function main() {
  const widget = await readWidget();
  if (!widget) throw new Error('no jsapi.js script or apiKey in the page HTML');
  for (let attempt = 1; attempt <= 3; attempt++) {
    try {
      const token = await getToken(widget); // exchange at once, never store it
      const res = await submitForm(token);
      console.log(res.status, await res.text());
      return;
    } catch (err) {
      if (!(err instanceof ApiException)) throw err;
      console.log(`attempt ${attempt}: ${err.message}`); // each retry draws a new puzzle
    }
  }
  throw new Error('AWS WAF CAPTCHA not solved in 3 attempts');
}

main().catch((err) => {
  console.error(`${err.constructor.name}: ${err.message}`);
  process.exitCode = 1;
});

mock रन में script ने इस तरह व्यवहार किया:

mock सेटिंगscript ने क्या किया
हर puzzle का जवाब दिया गयाएक टास्क, voucher की एक अदला-बदली, फिर status 200 और टेक्स्ट Message sent
पहले दो puzzle ठुकराए गएदो attempt लाइनें, फिर तीसरे टास्क पर status 200
पहले तीन puzzle ठुकराए गएतीन attempt लाइनें, फिर error लाइन और exit code 1

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

आम errors

त्रुटिकारणफिक्स
no jsapi.js script or apiKey in the page HTMLपेज विजेट को एक bundle से बनाता है, इसलिए HTML में वे values नहीं होतींलोड हुई scripts में apiKey और jsapi.js खोजें, फिर values हाथ से पास करें
ValidationExceptioncontext के बिना iv, या ऐसा script पता जो awswaf.com host पर पूरा https पता न होविजेट के लिए iv या context न भेजें, और jsapi.js का पता वैसा ही कॉपी करें जैसा पेज में है
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 exchange failed: HTTP 4xxज़्यादातर संभावना यही है कि जोड़ी पुरानी है या मेल नहीं खाती, या TOKEN_BASE गलत है। CapSkip app का कोड अमान्य existing_token के लिए AWS से HTTP 400 की उम्मीद करता है। असली AWS के सामने इसे दोहराया नहीं जा सकातुरंत अदला-बदली करें, Network tab में folder जाँचें, और नया टास्क सबमिट करें
फ़ॉर्म की post अब भी ठुकराई जा रही हैटोकन की अवधि खत्म हो गई, या पेज उसे header में लेता है और आपने cookie भेजीवही कॉपी करें जो पेज की अपनी रिक्वेस्ट ले जाती है

सॉल्वर को किसी 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

विजेट पेज को 405 challenge पेज से कैसे अलग पहचानें?

challenge पेज रिक्वेस्ट का जवाब HTTP 405 से देता है और gokuProps परिभाषित करता है। विजेट पेज एक सामान्य पेज होता है जो jsapi.js लोड करता है और renderCaptcha को call करता है, आमतौर पर किसी फ़ॉर्म पर। दोनों को एक ही amazonWaf method संभालता है, अलग values के साथ।

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

आपकी script को ब्राउज़र की ज़रूरत नहीं। वह CapSkip और साइट को सादी HTTP रिक्वेस्ट भेजती है, और CapSkip उस मशीन पर, जहाँ वह चलता है, puzzle को असली ब्राउज़र में हल करता है, जैसा SDK दस्तावेज़ बताते हैं। ब्राउज़र आपको खुद सिर्फ़ एक बार खोलना होता है, पेज से values पढ़ने के लिए।

क्या SDK टोकन सीधे लौटाता है?

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

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

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

संक्षेप में

Node.js में AWS WAF CAPTCHA विजेट पर वही puzzle है जो 405 पेज पर होता है, बस जगह अलग है: apiKey और jsapi.js का पता पढ़ें, amazonWaf को call करें, जोड़ी को voucher endpoint पर बदलें, और टोकन उसी तरह भेजें जैसे पेज भेजता है। CapSkip एक कैप्चा बायपास है जो आपकी अपनी मशीन पर चलता है, इसलिए जिस puzzle का वह जवाब नहीं दे पाता, उसकी कीमत एक दोबारा कोशिश है, कोई शुल्क नहीं। SDK की बाकी जानकारी के लिए देखें: Node.js कैप्चा सॉल्वर पेज.