عبور از Captcha و حل خودکار آن

Captcha ها معمولا برای مسدود کردن افراد خراب کاری به کار می رود که قصد کلاهبرداری یا دستکاری داده ها را دارند با در کمپین های تبلیغاتی مختلف میلیون ها حمله انجام می دهند. دلایل زیادی وجود داره که بخواهید یک سایت رو از طریق برنامه ای که نوشتید کنترل کنید و مسلما Captcha نمیتونه جلوی شما رو بگیره

عبور از Captcha و حل خودکار آن

اکنون بیش از چند سال است که با Captcha ها سر و کار دارید. آن همه خط و کلمه و عدد که راه شما را سد می کنند. به هنگام ورود ، ثبت نام یا ارسال نظر در هر جایی!

اینا رو کی میتونه بخونه واقعا ؟

Captcha مخفف عبارت Completely Automated Public Turing tests to tell Computers and Humans Apart یا معدل فارسی ( تست های تورینگ عمومی کاملا خودکار جهت تشخیص رایانه ها و انسان ها ) است و به گونه ای طراحی شده اند تا مانند دروازه ای خاص ، انسان ها را از خود عبور دهند و جلوی ربات ها را بگیرند. البته خطوط و بی معنا و کلمات ناخوانای سنتی این روزها کمتر رایج هستند و جای خودشون رو به reCaptcha گوگل دادند. این کپچا به هنگامی که ضریب انسانیت شما را بالا در نظر بگیرد به صورت خودکار تیک سبزی نشان داده و اجازه عبور می دهد.

Google reCAPTCHA v2

اگر امتیازی بالاتر از آستانه در نظر گرفته شده کسب نکنید ، کپچا شما رو به یک چالش تصویری جذاب دعوت میکنه و پازلی در اختیار شما میذاره که واقعا حل اون آزاردهنده تر از رمزگشایی کپچاهای سنتی !!!

reCAPTCHA Puzzle

کپچا برای انسان آزاردهنده است ، ولی اگر حداقل کارشون رو انجام بدن و ما رو با پازل های مختلف درگیر نکنن میشه اون ها رو تحمل کرد ( ایده ای که منجر به انتشار نسخه سوم reCaptcha یا Invisible Captcha شد ). اما راه ساده تر از اثبات انسان بودن ، حل خودکار کپچاها است.
اینجا است که به سراغ 2Captcha می رویم.

2Captcha چطور کار می کنه ؟

این ابزار گونه های مختلفی از کپچا را حل می کند که این روند قالبا در دو مرحله انجام می شود. ابتدا داده های لازم برای حل کپچا را ارسال کرده و یک Request ID تحویل می گیرد. در صورتی که کپچا به صورت عکس باشد این داده ها شامل رشته Base64 آن عکس است.

در مرحله بعد درخواست خودتون رو ثبت می کنید و منتظر جواب کپچا می‎مونید !

تا اینجای کار همه چیز ساده است. اما وقتی به سراغ Google reCaptcha می‎رید داستان کمی فرق داره. شما همچنان درگیر همون 2 مرحله قبل هستید فقط داده های متفاوتی رو ارسال می کنید. در این مورد باید Site Key مربوط به reCaptcha رو ارسال کنید. این مقدار به صورت پیشفرض در بدنه HTML سایت قرار می گیره.

How to get sitekey

پاسخی که از کپچا دریافت میشه یه Token که باید در کنار باقی فیلدهای فرم با شناسه g-recaptcha-response ارسال بشه. برای مثال به تصویر زیر نگاه کنید. ( نسخه دمو reCaptcha v2 که خود گوگل منتشر کرده ). فیلد توکن با استایل display: none در فرم قرار میگیره تا در نهایت Submit بشه. این که فیلد متنی در اختیار شما است یعنی به راحتی میتونید مقدار اون رو ویرایش کنید تا آزمایش های خودتون رو انجام بدید. این گزینه کمک بزرگی به کاهش زمان Bypass میکنه.

Hidden captcha token

برای کپچاهای مبتنی بر تصویر ، نتیجه تقریبا در لحظه حاصل میشه ولی برای reCaptcha نسخه 2 چیزی حدود 15 تا 30 ثانیه طول میکشه ( به Timeout کپچا نمیرسه خیالتون راحت 😉 )

خودکار سازی روند Bypass

قبل از اینکه خودتون رو درگیر کپچا کنید ، باید ابزارهای خودتون رو انتخاب کنید. مسلما نمیشه درخواست ها رو دستی به سرور ارسال کرده و نتایج رو دریافت و در فرم قرار بدید. در ضمن کل روند Bypass کردن برای تست و آزمایش و رد کردن کپچاها در شبیه ساز هاست ( کارهای دیگه ای هم میشه کرد ولی بیاید خوش بینانه فکر کنیم و کلاه سفید باشیم ). 😁

در اولین مرحله به یک مرورگر نیاز داریم چون که با وب سایت و برنامه تحت وب سر و کار داریم. به شخصه روزمره از Firefox استفاده می کنم و تست ها و اتوماسیون ها رو با Google Chrome انجام میدم. فایرفاکس هم جواب میده و برای اتوماسیون ، کروم بهتر عمل میکنه.

در مرحله بعد کتابخانه ای برای اتوماسیون خودمون نیاز داریم. پیشنهاد من Puppeteer. با استفاده از این کتابخانه شما حتی نیاز به نصب گوگل کروم هم ندارید چون به صورت پیشفرض به همراه خودش نسخه ای از Chromium رو نصب می کنه. البته در صورت نیاز می تونید از نسخه ی کروم که خودتون جدا نصب کردید هم استفاده کنید ، مشکلی نیست.

با دستور زیر Puppeteer رو نصب کنید :

npm i puppeteer
# or
yarn add puppeteer

با اجرای این دستور آخرین نسخه puppeteer به همراه مرورگر مربوطه نصب میشه. ( حجمی در حدود 200 مگابایت ). در صورتی که نیاز به دانلود و نصب مجزای مرورگر ندارید از متغییر PUPPETEER_SKIP_CHROMIUM_DOWNLOAD استفاده کنید. یا خیلی ساده می تونید از puppeteer-core استفاده کنید. این نسخه مرورگری رو به همراه خودش نصب نمیکنه و فقط فایل های اصلی کتابخانه رو در اختیار شما قرار میده.

npm i puppeteer-core
# or
yarn add puppeteer-core

برای مقایسه بهتر نسخه معمولی و Core به این آدرس مراجعه کنید.

تست و شروع به کار

بعد از اینکه مطمئن شدید همه چیز نصب شده و آماده به کاره وقتشه تا یه تست کوچیک انجام بدیم. برای مثال یک وب سایت رو باز کنیم. بریم سراغ وب سایت Dice :

const puppeteer = require("puppeteer-core");

(async () => {
  let launchOptions = {
    headless: false,
    executablePath:
      "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
    defaultViewport: null,
  };

  const browser = await puppeteer.launch(launchOptions);
  const page = await browser.newPage();

  await page.goto("https://www.dice.com/register");
})();

در اینجا ما سه گزینه را تنظیم می کنیم :

  • ویژگی headless رو غیرفعال می کنیم تا مرورگر باز بشه و خودمون همه چیز رو مشاهده کنیم
  • با استفاده از گزینه executablePath می تونیم آدرس فایل اجرایی مرورگر رو به برنامه بدیم. برای مثال اینجا از نسخه ویندوز استفاده شده.
  • با استفاده از defaultViewport اندازه های پیشفرض صفحه رو کامل غیرفعال می کنیم تا مشکلی با وب سایت های مختلف نداشته باشیم. برای مثال اگه مرورگر رو Maximize باز کنید ، وب سایت به طور کامل کل صفحه رو پر نمیکنه.

تا اینجای کار که ساده بود! حالا بریم سراغ مراحل بعدی کار تا کم کم اتوماسیون خودمون رو راه بندازیم. ابتدا باید فیلد های خودمون رو در صفحه شناسایی کنیم. تمام مرورگر ها ابزار Inspect/devtools دارن. این ابزار با کلید F12 باز میشه و سپس باید المان های مختلف رو پیدا کنیم. ترکیب Ctrl+Shift+C در ویندوز و Shift+C+⌘ در مک. اینجا در وب سایت Dice ما 5 فیلد داریم که باید پر بشه.

  • First Name = #fname
  • Last Name = #lname
  • Email = #email
  • New Password = #password
  • Retype Password = #passwordConfirmation

حالا باید داده های خودمون رو در فیلدهای بالا وارد کنیم. این کار هم به سادگی انجام میشه و تابعی به اسم type برای اون در اختیار داریم :

await page.type("#fname", "FirstName");
await page.type("#lname", "LastName");
await page.type("#email", "mail@domain.com");
await page.type("#password", "StrongP@ssw0rd#");
await page.type("#passwordConfirmation", "StrongP@ssw0rd#");
How to get input's id
Fill the form automatically

شبیه سازی کلیک روی دکمه Register هم به سادگی مراحل قبل بوده و با تابع click انجام میشه :

await page.click("#people button[type=submit]");

حالا با اجرای کد ، ثبت نام به صورت خودکار انجام میشه ولی خب مسلما کار نمیکنه چون Captcha رو رد نکردیم !

راه اندازی 2Captcha

ابتدا در وب سایتشون ثبت نام کرده و کلید API خودتون رو دریافت کنید.

2Captcha API Key

روند کار API به این صورته که داده های کپچا رو به 2Captcha ارسال می کنید و نتایج رو دریافت می کنید. ولی اینجا با reCaptcha طرف هستیم و در نتیجه باید تغییراتی را هم داشته باشیم

  • به reCaptcha SiteKey نیاز داریم که اول پست توضیح دادم. این مقدار در کدهای جاوا اسکریپت قرار داره که با جستجو در devtools می تونید اون رو پیدا کنید.
Sitekey
  • باید method روی userrecaptcha قرار داده بشه
  • آدرس صفحه نیز باید ارسال بشه
const formData = {
  method: "userrecaptcha",
  key: apiKey,
  googlekey: "6LcleDIUAAAAANqkex-vX88sMHw8FXuJQ3A4JKK9",
  pageurl: "https://www.dice.com/register",
  json: 1,
};

const response = await request.post("http://2captcha.com/in.php", {
  form: formData,
});

const requestId = JSON.parse(response).request;

بعد از اینکه درخواست خودتون رو ارسال کردید و Request ID دریافت شد ، باید از اون برای دریافت نتیجه استفاده کنید و به چنین آدرسی درخواست بفرستید :

http://2captcha.com/res.php?key=${apiKey}&action=get&id=${reqId}

در صورتی که کپچای شما حاضر نباشد جواب CAPTCHA_NOT_READY دریافت خواهید کرد که یعنی باید چند ثانیه دیگه مجدد تست کنید. وقتی که کپچا حاضر باشه پاسخ شما داده میشه که برای کپچا های عادی ، جواب اون و برای reCaptcha مقدار مورد نظر جهت قرار دادن در فرم برای Submit خواهد بود.

برای reCaptcha v2 این فرایند 15 الی 30 ثانیه ( شایدم بیشتر ) طول بکشه. در ادامه نمونه کد مربوطه رو مشاهده می کنید :

async function pollForRequestResults(
  key,
  id,
  retries = 30,
  interval = 1500,
  delay = 15000
) {
  await timeout(delay);
  return poll({
    taskFn: requestCaptchaResults(key, id),
    interval,
    retries,
  });
}
function requestCaptchaResults(apiKey, requestId) {
  const url = `http://2captcha.com/res.php?key=${apiKey}&action=get&id=${requestId}&json=1`;
  return async function () {
    return new Promise(async function (resolve, reject) {
      const rawResponse = await request.get(url);
      const resp = JSON.parse(rawResponse);
      if (resp.status === 0) return reject(resp.request);
      resolve(resp.request);
    });
  };
}
const timeout = (millis) =>
  new Promise((resolve) => setTimeout(resolve, millis));

در اینجا طی یک بازه زمانی تعیین شده بررسی می کنیم که آیا کپچای ما حل شده یا نه. تا در سریع ترین زمان ممکن و قبل از رسیدن به Timeout فرم خودمون رو ثبت کنیم.

بعد از این که پاسخ دریافت شد ، باید اون رو در فیلد g-recaptcha-response که بالاتر توضیح دادم قرار بدید. این کار هم که با تابع type انجام میشه ولی به همین سادگی هم نیست چون این فیلد در حال عادی مخفی بوده و این تابع جواب نمیده. حالا دو تا راه داریم :

  • فیلد رو Visible کنید و سپس از تابع type استفاده کنید ❌
  • با استفاده از جاوا اسکریپت مقدار رو در فیلد قرار بدیم ✔

مورد دوم ساده تره ! و خب مسلما تابع آماده ای هم براش هست. اینجا می تونیم از تابع evaluate استفاده کنیم :

const response = await pollForRequestResults(apiKey, requestId);

const js = `document.getElementById("g-recaptcha-response").innerHTML="${response}";`;

await page.evaluate(js);

وقتی توکن به فرم اضافه شد ، همه چیز آماده است تا ثبت نام خودمون رو انجام بدیم. به همین سادگی ! فقط یکم تمیزکاری نیاز دارید.

نکته : جهت سرگرمی بیشتر و اینکه همه چیز رو مرحله به مرحله مشاهده کنید می تونید از متغییر slowMo استفاده کنید 😎

پروژه و کد کامل این پست رو در گیت هاب می تونید مشاهده کنید :

MyWebSite_Projects/2captcha at master · hatamiarash7/MyWebSite_Projects
Example projects that explained in my website. Contribute to hatamiarash7/MyWebSite_Projects development by creating an account on GitHub.