C#'ta Cloudflare Turnstile Doğrulama Sayfaları Nasıl Çözülür

turnstile challenge page - How to Solve Cloudflare Turnstile Challenge Pages in C#

Cloudflare Turnstile iki biçimde gelir ve her biri için C# kodu farklıdır. Bir forma gömülü widget için bir sitekey ve bir URL'den başka bir şey gerekmez. Tam sayfa ara doğrulama (interstitial challenge) ise sayfadan çıkarılan iki ek değere ihtiyaç duyar ve yalnızca çözücünün kullandığı user agent'ı geri gönderirseniz kabul edilir. Bu son kısmı atlarsanız, kusursuz görünen ama her seferinde doğrulamada başarısız olan bir token elde edersiniz.

Bu kılavuz, çalışan .NET koduyla her ikisini de kapsar.

Widget mı yoksa challenge sayfası mı?

Herhangi bir kod yazmadan önce hangisine baktığınızı belirleyin.

Bileşen moduDoğrulama sayfası
GördüğünüzHâlâ etkileşimde bulunabileceğiniz, bir formun içindeki onay kutusuTam sayfa bir ara sayfa (interstitial), genellikle “Checking your browser”
Sayfanın geri kalanıNormal şekilde yüklenirChallenge geçilene kadar engellenir
Gerektirir data / pagedataHayırEvet
Döndürülen user agent'ı gerektirirHayırEvet

Emin değilseniz, bizim canlı Turnstile demo sayfası bileşen çeşidini çalıştırır, böylece onu gerçekte karşılaştığınız her neyse onunla karşılaştırabilirsiniz.

Kurulum

CapSkip kendi makinenizde çalışır, dolayısıyla bunların herhangi biri çalışmadan önce başlatılacak yerel bir hizmet vardır. SDK'yı NuGet'ten kurun:

# .NET Standard 2.0, so this works on .NET Framework 4.6.1+,
# .NET Core 2.0+, and .NET 6 through 9.
dotnet add package CapSkip

Ardından istemciyi, CapSkip uygulamasında gösterilen porta yönlendirin:

using CapSkip;

var solver = new CapSkipClient(
    apiKey: "capskip",        // any string when key validation is off
    host: "127.0.0.1",
    port: 8080,
    recaptchaTimeout: 300);   // seconds, also covers Turnstile and GeeTest

Bileşen modu, kolay durum

İki argüman ve işiniz biter:

var result = await solver.TurnstileAsync(
    "0x4AAAAAAA...",                  // sitekey from the data-sitekey attribute
    "https://example.com/login");

Console.WriteLine(result.Code);       // cf-turnstile-response token

Bırak result.Code şunun içine: cf-turnstile-response alan ve formu gönderin. Yapılacak başka bir şey yok.

Doğrulama sayfaları iki değer daha gerektirir

Bir ara sayfa challenge'ı, token'ın bağlı olduğu istek başına durum taşır. Bunun iki parçasının çözüm isteğinizle birlikte gitmesi gerekir:

  • cData, şu olarak geçirilir: data
  • chlPageData, şu olarak geçirilir: pagedata

Her ikisi de bir form özniteliği yerine challenge sayfasının kendisine gömülüdür; bu nedenle çözebilmek için önce sayfayı okumanız gerekir. Standart bir Cloudflare ara sayfasında bunlar, sitekey ile birlikte sayfanın kendi challenge seçenekleri nesnesinde açığa çıkarılır.

Ayrıca tek kullanımlıktır ve o belirli sayfa yüklemesine bağlıdır. Onları getirin, hemen çözün ve denemeler arasında önbelleğe almayın.

using System.Collections.Generic;
using CapSkip;

var result = await solver.TurnstileAsync(
    sitekey,
    pageUrl,
    new Dictionary<string, object?>
    {
        ["data"]     = cData,          // the cData value from the page
        ["pagedata"] = chlPageData,    // the chlPageData value
        ["action"]   = "managed",       // optional, when the page declares one
    });

Console.WriteLine(result.Code);
Console.WriteLine(result.UserAgent);   // you are going to need this

Herkesin kaçırdığı kısım: user agent

Turnstile, token'ı onu üreten tarayıcı parmak iziyle ilişkilendirir ve user agent bunun bir parçasıdır. CapSkip, kullandığı değeri şurada döndürür result.UserAgent. Ardından token'ı şuradan gönderirseniz: HttpClient kendi varsayılan user agent'ını gönderdiğinde, değerler eşleşmez ve Cloudflare, aksi halde tamamen geçerli olan bir token'ı reddeder.

UserAgent yalnızca Turnstile için doldurulur. Diğer her CAPTCHA türü için null'dır; işte bu yüzden çalışan bir reCAPTCHA yardımcısını yeniden kullanan insanların kafasını karıştırır.

using System.Net.Http;
using CapSkip;

var result = await solver.TurnstileAsync(sitekey, pageUrl, options);

using var http = new HttpClient();

// Send back the exact user agent the solve was performed with.
http.DefaultRequestHeaders.UserAgent.ParseAdd(result.UserAgent);

var form = new FormUrlEncodedContent(new[]
{
    new KeyValuePair<string, string>("cf-turnstile-response", result.Code),
});

var response = await http.PostAsync(pageUrl, form);

Token'ınız reddediliyorsa ve süresi dolmuş bir seçeneği eledeyseniz cData, neredeyse her zaman neden budur.

Başarısızlıkları doğru şekilde ele alma

Her SDK istisnası (exception) şundan türer: CapSkipError, böylece o tek türü yakalayabilir veya her birini ayrı ayrı ele alabilirsiniz. Bilinmeye değer .NET'e özgü bir tuzak vardır.

using System;
using CapSkip;

try
{
    var result = await solver.TurnstileAsync(sitekey, pageUrl, options);
}
catch (CapSkip.ValidationException)   { /* bad parameters */ }
catch (NetworkException)              { /* CapSkip is not running */ }
catch (ApiException)                  { /* API returned an error code */ }
catch (CapSkip.TimeoutException)      { /* exceeded recaptchaTimeout */ }
catch (CapSkipError)                  { /* anything else from the SDK */ }

TimeoutException ve ValidationException her ikisinde de bulunur System ve CapSkip. Her iki ad alanı da içe aktarıldığında, niteliksiz bir catch (TimeoutException) şuna çözümlenir System biri ve sessizce hiç tetiklenmez. Bunları yukarıdaki gibi nitelendirin ya da yalnızca şunu yakalayın: CapSkipError ve inceleyin.

Aynı anda birkaç tanesini çözme

Her metot bir şey döndürür Task, böylece sıradan .NET eşzamanlılığı geçerlidir:

var results = await Task.WhenAll(
    solver.TurnstileAsync(sitekeyA, "https://a.example.com"),
    solver.TurnstileAsync(sitekeyB, "https://b.example.com"));

foreach (var r in results)
{
    Console.WriteLine(r.Code);
}

SDK ayrıca şunları dışa aktarır: AsyncCapSkip, ancak .NET'te yalnızca şunun bir takma adıdır: CapSkipClient. Python SDK'sından taşınan kodun derlenmeye devam etmesi için vardır. Ona geçmek size hiçbir şey kazandırmaz, çünkü .NET I/O zaten eşzamansızdır.

Bir proxy üzerinden yönlendirme

Challenge coğrafi konuma duyarlıysa, göndereceğiniz ağ yolunun aynısından çözün:

var result = await solver.TurnstileAsync(sitekey, pageUrl,
    new Dictionary<string, object?>
    {
        ["data"]     = cData,
        ["pagedata"] = chlPageData,
        ["proxy"]    = new Proxy("HTTPS", "user:[email protected]:3128"),
    });

Proxy'ler Turnstile, reCAPTCHA ve GeeTest için desteklenir. Görsel baytlarından çözülen ve asla hedef siteye dokunmayan görsel CAPTCHA'lar için desteklenmez.

Sık sorulan sorular

Her zaman cData ve chlPageData'ya ihtiyacım var mı?

Hayır. Yalnızca tam sayfa ara challenge'lar için. Bir formun içinde yer alan bir Turnstile widget'ı sitekey ve sayfa URL'sinden başka hiçbir şeye ihtiyaç duymaz ve bir widget'ta boş değerler geçmek, çözüme yardımcı olmak yerine başarısız olmasına neden olur.

Token'ım geçerli ama site onu yine de reddediyor. Neden?

Neredeyse her zaman user agent. Turnstile, token'ı onu üreten parmak iziyle ilişkilendirir; bu nedenle şuradaki değeri kullanarak göndermeniz gerekir result.UserAgent. İkinci en yaygın neden bayat bir cData, ki bu tek bir sayfa yüklemesine bağlıdır.

.NET Framework'te çalışır mı?

Evet. Paket .NET Standard 2.0'ı hedefler; bu nedenle .NET Framework 4.6.1 ve daha yenisinde, .NET Core 2.0+'da ve her modern .NET sürümünde çalışır. Senkron koddan çağırabilirsiniz .GetAwaiter().GetResult(), ancak düzgün şekilde await etmek daha iyidir.

Bir Turnstile çözümü ne kadar sürmelidir?

Genellikle birkaç saniye. İstemci dahili olarak yoklama (polling) yapar; 250ms'de başlar ve şuraya kadar geri çekilir: pollingInterval, ve şurada vazgeçer: recaptchaTimeout varsayılan olarak 300 saniyedir. Bu tavana sürekli takılıyorsanız, zaman aşımı süresini artırmak yerine CapSkip hizmetinin gerçekten çalışıp çalışmadığını kontrol edin.

Özet

Widget Turnstile iki argümanlı bir çağrıdır. Sorgu sayfaları şuna ihtiyaç duyar data ve pagedata sayfadan taze okunur ve token, yanında döndürülen user agent ile gönderilmelidir. Şunu yakalayın: CapSkipError ad alanı çakışmasıyla uğraşmak yerine ve challenge coğrafyaya duyarlı olduğunda bir proxy kullanın.

.NET için tam metot yüzeyi şurada bulunur: C# CAPTCHA çözücü sayfası, parametre referansı şuradadır: API dokümantasyonu, ve Turnstile desteği diğer dilleri kapsar. CapSkip'in kendisi bir sınırsız captcha çözücü yerel olarak çalışır; dolayısıyla yukarıdakilerin hiçbiri çözüm başına maliyet oluşturmaz.