سرویس کپچای متنی چگونه کار می‌کند؟

وقتی شما ثبت‌نام کردید، به شما یک کلید API داده می‌شود. این کلید یک کلید منحصربه‌فرد برای وب‌گاه شماست، مانند رمز عبور. برای آزمایش شما می‌توانید از کلید «demo» استفاده کنید که از یک مجموعه کوچک از سوالات استفاده می‌کند.

هر وقت شما نیاز به یک سوال منطقی داشتید، می‌توانید درخواستی به سرور ما بفرستید. آن یک پاسخ XML که شامل یک سوال و جواب تصادفی است را برمی‌گرداند. برای جلوگیری از کاربران مزاحم (ربات‌ها) جواب‌ها با استفاده از الگوریتم MD5، تبدیل به Hash می‌شوند. این به شما اجازه می‌دهد بدون دانستن جواب، جواب کاربر را Hash کنید و با Hash اصلی مقایسه کنید.

در زیر چندین مثال با استفاده از زبان پی‌اچ‌پی آورده شده‌است که نشان می‌دهد چگونه می‌توان از این سرویس در وب‌گاه خود استفاده کنید. در زبان‌های دیگر نیز پلاگین‌هایی برای کار با کپچای متنی نوشته شده‌است:

استفاده پایه

URL برای دریافت پاسخ XML کپچای متنی:

http://api.textcaptcha.ir/your_api_key

نمونه‌ای از پاسخ XML به صورت زیر است:

  <captcha>
    <question>اگر فردا جمعه باشد، امروز چه روزی است؟</question>
    <answer>2cf0a16e46fe60f46860b4a85d8d8267</answer>
    <answer>b2b62f03dd1e10f6c069fc38998bcbf4</answer>
    <answer>32da14ea4ea092878fb3b1209437ff2a</answer>
    <answer>2a6e26fd11c7934fcd8a9c8ef605dc89</answer>
    <answer>bf03b48482f59ea0f3622bb1b55ce750</answer>
    <answer>e6b059b2f172b05ff1b930a75e36e5fd</answer>
  </captcha>

در مثال XML بالا، ۶ جواب ممکن است وجود داشته باشد، «پنج‌شنبه»، «پنج شنبه»، «۵شنبه»، «۵ شنبه»، «5شنبه» و «5 شنبه». تمام جواب‌ها MD5 شده‌اند. توجه کنید که در سیستم‌عامل ویندوز به‌دلیل استفاده نشدن از کیبورد استاندارد فارسی، اعداد به انگلیسی نیز جواب صحیح محسوب می‌شوند. شما آزادید که چگونه این را پیاده‌سازی کنید. این مثال زیر در پی‌اچ‌پی نسخهٔ ۵ نوشته شده‌است و از simpleXML استفاده می‌کند.
نخستین قدم گرفتن کپچا و قرار دادن سوال در فرم کاربر و ذخیره کردن جواب آن در متغیر session است.

  <?php
  session_start();

  // load captcha using web service
  $url = 'http://api.textcaptcha.ir/my_api_key';
  try {
    $xml = @new SimpleXMLElement($url,null,true);
  } catch (Exception $e) {
    // if there is a problem, use static fallback..
    $fallback = '<captcha>'.
        '<question>آیا یخ داغ است یا سرد؟</question>'.
       '<answer>'.md5('سرد').'</answer></captcha>';
    $xml = new SimpleXMLElement($fallback);
  }

  // display question as part of form
  $question = (string) $xml->question;
    // ... [snip] ...

  // store answers in session
  $ans = array();
  foreach ($xml->answer as $hash)
    $ans[] = (string) $hash;
  $_SESSION['captcha'] = $ans;

وقتی فرم فرستاده شد، جوابی که توسط کاربر داده شده‌است باید با جوابی که در session ذخیره شده‌است، اعتبارسنجی شود. شما باید ابتدا جواب کاربر را trim کنید و سپس آن‌را MD5 hash کنید و سپس با جوابی که در session ذخیره شده‌است مقایسه کنید.

  <?php
  session_start();
  $ans = $_POST['captcha']; // .. or whatever!
  $ans = strtolower(trim($ans));
  $ans = md5($ans);

  if (in_array($ans,$_SESSION['captcha'])) {
      // passed..!
  } else {
      // error: redisplay form, etc.
  }

استفاده پیشرفته

شما می‌توانید جواب‌ها را در داخل یک ورودی پنهان نیز قرار دهید. اما توجه کنید اگر از salt استفاده نکنید پیاده‌سازی شما ضعیف خواهد بود. برای مثال یک ربات ممکن است با hash کردن تک تک کلمات سوال و مقایسه کردن آن ورودی پنهان به جواب صحیح دست پیدا کند. برای این‌که در مقابل این نوع حملات محافظت شوید، از salt باید استفاده کنید.

  <?php
  $salt = 'MySecretSalt';

  // ... [snip] ...

  // output hidden form fields
  foreach ($xml->answer as $hash) {
    $ans = md5($hash.$salt);
    echo '<input type="hidden" name="ans[]" value="'.$ans.'" />';
  }

  // ... [snip] ...

  // on submission, validate against hidden fields
  $user_ans = $_POST['captcha']; // .. or whatever!
  $user_ans = strtolower(trim($user_ans));
  $user_ans = md5(md5($user_ans).$salt);
  if (in_array($user_ans,$_POST['ans'])) {
     // passed..!
  } else {
     // error: redisplay form, etc.
  }

در پیاده‌سازی‌هایی که از session استفاده نمی‌کنید، باید توجه کنید که امکان دارد یک ربات از یک کپچا چندین و چند بار استفاده کند. برای مثال اگر ربات فرم را بارگیری کند و یک‌بار به صورت دستی جواب صحیح را وارد کند، آن‌گاه می‌تواند آن فرم را چندین و چند بار با استفاده از همان کپچا، بفرستند و آزمایش کپچا را با موفقیت پشت سر بگذارند. برای جلوگیری از این نوع حملات شما باید کپچایی که برای یک شی فرم ساخته می‌شود، قفل کنید و مطمئن شوید که از آن برای همان فرم استفاده شده‌است. این را می‌توان با استفاده از timeouts در فرم و تکنیک‌های دیگری که برای مقابله با حملات CSRF طراحی شده‌است، پیاده کرد. توضیح کامل آن خارج از این مقوله است، اما به‌یاد داشته باشید در پیاده‌سازی‌های خود آن‌را به‌درستی اعمال کنید.