C# ile Friendly Captcha Nasıl Çözülür (v1 ve v2 Widget’ları)

solve friendly captcha in c# - How to Solve Friendly Captcha in C# (v1 and v2 Widgets)

C# ile Friendly Captcha çözmek için FriendlyCaptchaAsync metodunu sitekey, sayfa URL’si ve widget sürümüyle çağırın, ardından token’ı o sürümün beklediği form alanına gönderin. İşin tamamı sürüme bağlıdır. Friendly Captcha tek bir ad altında iki farklı protokol sunar ve bu ikisi aynı sitekey ad alanını paylaşır; dolayısıyla anahtarın hiçbir yeri size bir sitenin hangisini çalıştırdığını söylemez. Yanlış olanı çözerseniz, sitenin hiçbir gerekçe göstermeden reddettiği, biçimce kusursuz bir token elde edersiniz. CapSkip, Friendly Captcha desteğini 1.4.0 sürümünde ekledi. Bu rehber ikisini birbirinden ayırt etmeyi, çağrıyı ve gönderimi ele alıyor.

Neye ihtiyacınız var

  • Bir Windows makinesinde çalışan CapSkip 1.4.0 veya üzeri. Friendly Captcha desteği, CaptchaFox ve Capy Puzzle ile birlikte bu sürümle geldi.
  • CapSkip .NET paketinin 1.3.0 veya üzeri bir sürümü; FriendlyCaptchaAsync metodunu ekleyen sürüm budur. Paket .NET Standard 2.0’ı hedefler, yani .NET Framework 4.6.1 ve üzeri, .NET Core 2.0 ve üzeri ve .NET 6 ile sonrası sorunsuz çalışır. Örnekler üst düzey deyimler (top-level statements) kullanır, bu yüzden onları .NET 6 veya sonrasında çalıştırın.
  • Hedef sayfadan üç değer: widget öğesindeki sitekey, sayfanın kendi URL’si ve sayfanın yüklediği widget script’inin adresi. Her birinin nerede bulunduğunu 1. adım gösteriyor.
  • Çözücü için bir adres. Local modu 127.0.0.1 üzerinden yalnızca o cihaza yanıt verir; Server modu ise ağ adresinizi veya genel IP’nizi dinler, böylece başka bir makine onu API üzerinden çağırabilir. İkisi de bağlantı ayarları bölümünde yer alır; hangisini istediğinizi 4. adım anlatıyor.
# dotnet add package CapSkip
dotnet add package CapSkip

1. Adım: Friendly Captcha v1 ile v2’yi ayırt edin

Her iki sürüm de aynı öğeyi oluşturur: frc-captcha sınıfına ve bir data-sitekey özniteliğine sahip bir div. Yani öğe size sitekey’in nerede olduğunu söyler, protokol hakkında ise hiçbir şey söylemez. Sırrı ele veren, widget’ı yükleyen script etiketidir, çünkü v1 ve v2 farklı dosya adlarına sahip farklı paketlerdir.

Karşılaştırılacak noktaSürüm 1Sürüm 2
Sayfanın yüklediği paketfriendly-challenge@friendlycaptcha/sdk
Script dosyasıwidget.module.min.js, yedek olarak widget.min.jssite.min.js, yedek olarak site.compat.min.js
Token’ın gittiği form alanıfrc-captcha-solutionfrc-captcha-response
Bir token’ın görünümüNoktalarla ayrılmış dört parça, birkaç yüz karakter uzunluğundaAQQA ve bir noktayla başlayan tek parça opak bir dize, yaklaşık altı kilobayt

Sayfa kaynağını görüntüleyin, öğeyi bulmak için frc-captcha araması yapın, ardından onu yükleyen script etiketlerini okuyun. Friendly Captcha aynı kontrolü şurada belgeliyor: iki sürümü anlatan kendi sayfası. Site widget’ı kendisi barındırıyorsa paket adı URL’den kaybolabilir; bu durumda dosya adına bakın. Sitenin yaşına bakarak tahmin yürütmeyin: iki sürüm de yayında ve Friendly Captcha, v1’in bakımını birkaç yıl daha sürdüreceğini söylüyor.

2. Adım: FriendlyCaptchaAsync çağrısı

Tek metot, üç argüman: sitekey, sayfa URL’si ve bir seçenekler sözlüğü. 1. adımda bulduğunuz sürümü verin.

// dotnet add package CapSkip
using CapSkip;

var solver = new CapSkipClient(host: "127.0.0.1", port: 8080);

// Tell the solver which protocol the site runs.
var result = await solver.FriendlyCaptchaAsync(
    "YOUR_SITEKEY",
    "https://example.com/signup",
    new Dictionary<string, object?> { ["version"] = "v2" });

Console.WriteLine(result.Token);   // goes in frc-captcha-response

version seçeneği v1 veya v2 alır; yalın 1 veya 2 de çalışır. SDK başka herhangi bir değeri, daha hiçbir istek yapılmadan bir ValidationException ile reddeder. Bu bilinçli bir tercihtir: bir tahmin, sitenin çöpe attığı geçerli görünümlü bir token olarak geri dönerdi ve bu, bir hatadan daha kötüdür. Ancak null bir sürüm reddedilmez. Bu değer atlanır ve çözücü, aşağıda anlatıldığı gibi v1’e geri döner.

Token özelliğini okuyun. Code özelliği aynı dizeyi taşır, ancak Token adını içine gittiği alandan alır. User agent burada null kalır, çünkü yalnızca Turnstile ve CaptchaFox bir user agent bildirir.

Sürüme script adresinin karar vermesi

Kodunuzda widget script’inin adresi zaten varsa sürüm yerine onu verin; CapSkip sürümü, sitenin gerçekten yüklediği derlemeden okur ve bu, elde edilebilecek en güvenilir işarettir. Çözücü sabit bir sırayla kontrol eder ve ilk cevapta durur: önce version seçeneği, sonra script adresi, en son da varsayılan v1.

// Instead of the call above: copy the src straight off the page's module script tag.
var result = await solver.FriendlyCaptchaAsync(
    "YOUR_SITEKEY",
    "https://example.com/signup",
    new Dictionary<string, object?>
    {
        ["module_script"] =
            "https://cdn.jsdelivr.net/npm/@friendlycaptcha/[email protected]/site.min.js",
    });

Elinizdeki yedek script ise nomodule_script seçeneği aynı işi o script ile yapar. Ancak bu sıranın son adımına dikkat edin. Ne sürüm ne de script adresi verilmişse çözücü v1 varsayar; dolayısıyla yalnızca sitekey ile çözülen bir v2 sitesi, bu rehberin baştan sona uyardığı şekilde başarısız olur.

EU endpoint’indeki siteler

Friendly Captcha, bulmacaları yalnızca Almanya’dan sunan bir veri yerleşimi seçeneği satıyor. Bu hizmeti kullanan bir v2 widget’ı genellikle eu değerine ayarlanmış bir data-api-endpoint özniteliği taşır; bunu gördüğünüzde aynı değeri api_server seçeneği olarak verin. Bu seçenek global (varsayılan), eu veya tam bir URL alır. İki endpoint de aynı sitekey için token üretir; dolayısıyla bunu yanlış yapmak yalnızca sitenin kendi doğrulamasında yakalanır, bu da yine sessiz türden bir hatadır.

3. Adım: token’ı doğru alana gönderin

İnsanları tuzağa düşüren ikinci şey alan adıdır; bu genellikle çalışan bir v1 entegrasyonu bir v2 sitesine yöneltildiği anda olur. Widget token’ını gizli bir input alanına yazar ve sizin isteğinizin de onu aynı yere koyması gerekir.

// version holds what you passed in Step 2; http is your HttpClient.
// v1 reads frc-captcha-solution, v2 reads frc-captcha-response.
var isV2 = version is "v2" or "V2" or "2";
var field = isV2 ? "frc-captcha-response" : "frc-captcha-solution";

var body = new FormUrlEncodedContent(new Dictionary<string, string>
{
    ["email"] = "[email protected]",
    [field] = result.Token!,
});

var response = await http.PostAsync("https://example.com/signup", body);

Bunun üstüne iki ayrıntı daha var. Bir site, widget öğesindeki bir öznitelikle alanın adını değiştirebilir: v2’de data-form-field-name, v1’de data-solution-field-name. Bu yüzden bu özniteliğe bakın, varsa değerini kullanın. Ayrıca bazı entegrasyonlar token’ı form gönderimi yerine bir JSON gövdesinde gönderir; bu yüzden DevTools’u açın, formu bir kez elle gönderin ve sayfanın gönderdiğini birebir taklit edin.

v2’de boyut önemlidir. Yaklaşık altı kilobaytlık bir token bir POST gövdesinde sorun çıkarmaz, ancak bir sunucunun sorgu dizesi sınırını aşabilir veya dar bir veritabanı sütununda kesilebilir; kesilmiş bir token da yanlış bir token gibi doğrulamadan geçemez. Token’ı bütün hâlde tutun ve bir kez gönderin. Friendly Captcha’nın doğrulaması, her iki sürümde de süresi dolmuş veya daha önce kullanılmış bir yanıtı reddeder; dolayısıyla bir token tek bir gönderim için geçerlidir ve vakit kaybetmeden gönderilmelidir.

4. Adım: zaman aşımları ve çözücünün nerede çalıştığı

Friendly Captcha bir iş kanıtıdır, ama milisaniyelik türden değil. Servis her isteğin ne kadar iş gerektirdiğine istek yapıldığı anda karar verir ve daha önce çok gördüğü adresler için bu değeri yükseltir. Ayrıca CapSkip her v2 widget’ını gerçek bir tarayıcıda çözer. Bu yüzden metot, varsayılan yoklama zaman aşımıyla değil, daha uzun olan reCAPTCHA yoklama zaman aşımıyla çalışır.

Yapıcı seçeneğiVarsayılanNeyi kapsar
recaptchaTimeout300 saniyeFriendly Captcha, CaptchaFox, reCAPTCHA ve GeeTest yoklaması
defaultTimeout120 saniyeGörsel, ALTCHA ve Capy yoklaması
pollingIntervalEn fazla 5 saniyeYoklama 0,25 saniyeden başlar ve kademeli olarak bu değere kadar çıkar

Uzun bir çalışma boyunca çözümler yavaşlıyorsa muhtemel sebep bu artan zorluktur ve çözüm daha fazla adrestir. Metot istek başına bir proxy kabul eder; CapSkip’te yapılandırılmış bir proxy havuzu da yükü sizin için dağıtır. Bu ikisini burada, çoğu türde olduğundan daha erken devreye almaya değer.

Örnekler 127.0.0.1 kullanıyor, çünkü kodunuz ile çözücü aynı makinede olduğunda doğru adres budur. Çağıran kod başka herhangi bir yerde, örneğin bir konteynerde, bir derleme ajanında veya bir VPS’te çalışmaya başladığında loopback yanlış makineyi gösterir ve ilk çözüm bir NetworkException fırlatır. CapSkip’i Server moduna alın; o zaman bunun yerine ağ adresinizi veya genel IP’nizi dinler, böylece bunların hepsi ona API üzerinden ulaşabilir. Rota internetten geçiyorsa statik bir genel IP kullanın ve beklediğiniz adresler için bir güvenlik duvarı kuralı ekleyin. Donanım yine sizin donanımınızdır ve çözüm başına ücretlendirme yine yoktur.

İstemci ortam değişkenlerini kendiliğinden okumaz. Tam örnekte olduğu gibi CAPSKIP_HOST değerini kendi kodunuzda okuyup constructor’a verin; böylece tek bir derleme hem masanızda hem de bir sunucuda çalışır.

Tam çalışan örnek

// dotnet add package CapSkip
using System.Text.RegularExpressions;
using CapSkip;

var pageUrl = "https://example.com/signup";
var http = new HttpClient();
var solver = new CapSkipClient(
    host: Environment.GetEnvironmentVariable("CAPSKIP_HOST") ?? "127.0.0.1",
    port: 8080);

// Read the sitekey off the widget element, in either attribute order.
var html = await http.GetStringAsync(pageUrl);
var widget = Regex.Match(html,
    "<[^>]*class=\"(?:[^\"]*\\s)?frc-captcha(?:\\s[^\"]*)?\"[^>]*>").Value;
var sitekey = Regex.Match(widget, "data-sitekey=\"([^\"]+)\"").Groups[1].Value;

// The package name in the script URL decides the version.
var v2 = html.Contains("@friendlycaptcha/sdk");
var v1 = html.Contains("friendly-challenge");
if (v1 == v2)
    throw new InvalidOperationException("Read the script tag and set the version by hand.");
var version = v2 ? "v2" : "v1";

try
{
    var result = await solver.FriendlyCaptchaAsync(sitekey, pageUrl,
        new Dictionary<string, object?> { ["version"] = version });

    // A site can rename the field on the widget element.
    var renamed = Regex.Match(widget,
        "data-(?:form|solution)-field-name=\"([^\"]+)\"").Groups[1].Value;
    var field = renamed.Length > 0 ? renamed
        : v2 ? "frc-captcha-response" : "frc-captcha-solution";
    var body = new FormUrlEncodedContent(new Dictionary<string, string>
    {
        ["email"] = "[email protected]",
        [field] = result.Token!,
    });

    // Post wherever the form's action attribute points.
    var response = await http.PostAsync(pageUrl, body);
    Console.WriteLine($"{(int)response.StatusCode} with a {version} token");
}
catch (CapSkip.ValidationException ex)
{
    // An empty sitekey or an unknown version, refused before any request.
    Console.WriteLine($"not sent: {ex.Message}");
}
catch (CapSkip.TimeoutException)
{
    Console.WriteLine("gave up waiting; recaptchaTimeout is 300 seconds");
}

Sürüm bir kez belirlenir ve iki kez kullanılır: çözüm için ve alan adı için; böylece ikisi asla birbiriyle çelişemez. Regex hiçbir şey bulamazsa widget genellikle HTML’e yazılmak yerine JavaScript ile oluşturulmuştur ve sitekey’i render edilmiş sayfadan ya da onu oluşturan script’ten okumanız gerekir. Bu metodun arkasındaki ham endpoint, kabul ettiği tüm parametrelerle birlikte şurada belgelenmiştir: API referansı. Paketin sunduğu diğer tüm metotlar ise şurada listelenir: C# CAPTCHA çözücü sayfası.

Sık görülen hatalar ve anlamları

GördüğünüzNedenDüzeltme
Site, CapSkip’in çözüldü olarak döndürdüğü bir token’ı reddediyorYanlış sürüm çözüldü; çoğu zaman bir v2 sitesine uygulanan varsayılan v1Script etiketini okuyup sürümü verin ya da script adresini verin
Sürüm doğru olduğu hâlde site token’ı reddediyorToken diğer sürümün alanına gitti ya da site alanın adını değiştirdiO sürümün alanını ya da v2’de data-form-field-name, v1’de data-solution-field-name içindeki adı kullanın
Site token’ı reddediyor ve widget’ta data-api-endpoint ayarlıSite bölgesel bir endpoint üzerinde çalışıyor, çözümde ise varsayılan endpoint kullanıldıÖzniteliğin değerini api_server seçeneği olarak verin
Daha hiçbir şey gönderilmeden gelen bir ValidationExceptionSitekey veya sayfa URL’si boştu, sürüm v1, v2, 1 ya da 2 değildi veya seçeneklerde metodun kabul etmediği bir anahtar vardıRegex’in öğeyi bulduğunu kontrol edin, sürüm değerini düzeltin ve bilinmeyen seçeneği çıkarın
İndirdiğiniz HTML’de frc-captcha öğesi yokSayfa widget’ı JavaScript ile oluşturuyorSitekey’i render edilmiş sayfadan ya da onu oluşturan script’ten okuyun
Bir kez çalışan token ikinci gönderimde başarısız oluyorFriendly Captcha her yanıtı yalnızca bir kez kabul eder ve yanıtların süresi dolarHer gönderim için yeniden çözün ve hemen gönderin
Uzun bir çalışma ilerledikçe yavaşlayan çözümlerServis, çok sık gördüğü bir adres için gereken işi artırıyorÇözümleri bir proxy havuzuna dağıtın
İlk çözümde bir NetworkExceptionCapSkip çalışmıyor ya da host ve port yanlışCapSkip’i başlatın, ardından Local modunda mı yoksa Server modunda mı olması gerektiğini kontrol edin
Derleme, belirsiz bir TimeoutException yüzünden başarısız oluyorO kısa adı hem CapSkip hem System tanımlıyorCapSkip.TimeoutException’ı tam olarak yazın veya CapSkipError’ı yakalayın

FAQ

C# ile Friendly Captcha çözmek için benim tarafımda bir tarayıcı gerekir mi?

Hayır. Kodunuzun bir HttpClient’tan başka hiçbir şeye ihtiyacı yok. CapSkip işi kendi çalıştığı makinede yapar; v2 için bu, widget’ı orada gerçek bir tarayıcıda çalıştırmak demektir ve metodun daha uzun zaman aşımını kullanmasının bir nedeni de budur. Sizin tarafınız bir sitekey, bir URL ve bir sürüm gönderir, karşılığında da gönderilecek bir dize alır; bu yüzden bir worker service ya da zamanlanmış bir iş içinde rahatça çalışır.

Bunun ALTCHA çözmekten farkı nedir?

İkisi de iş kanıtıdır ve benzerlik burada biter. ALTCHA’da challenge’ı ya da onun geldiği endpoint’i verirsiniz, hash işlemi milisaniyeler sürer ve metot 120 saniyelik varsayılan zaman aşımıyla çalışır. Friendly Captcha’da ise zorluğu servis her istek için ayrı belirler ve yoğun adresler için yükseltir, v2 bir tarayıcıda çözülür ve metot 300 saniyelik zaman aşımıyla çalışır. Ayrıca ALTCHA’nın tek bir alan adı vardır, Friendly Captcha’nın ise iki. ALTCHA tarafı şurada ele alınıyor: C# ALTCHA rehberi.

Barındırılan bir platformdaki .NET uygulaması çözücüye erişebilir mi?

Evet. Bağlantı ayarlarından CapSkip’i Server moduna alın; böylece loopback yerine bir ağ adresini dinler. O adresi kodunuzda CAPSKIP_HOST değişkeninden okuyun ve istemciye verin. Bir konteyner sunucusu, bir VPS, bir CI ajanı ve yönetilen bir uygulama servisi; hepsi aynı şekilde, aynı HTTP API üzerinden bağlanır. Rota internetten geçiyorsa statik bir genel IP ve bir güvenlik duvarı kuralı kullanın. Çözücü sizin sahip olduğunuz donanımda kalır, dolayısıyla lisans veya çözüm sayısı açısından hiçbir şey değişmez.

Önceden toplu olarak token çözebilir miyim?

İşe yarar bir şekilde hayır. Her yanıt yalnızca bir kez kabul edilir ve süresi dolar; Friendly Captcha her iki durumu da siteye başarısızlık olarak bildirir. Biriktirdiğiniz stok bir ret yığınına dönüşür. Göndermek üzereyken çözün ve bunun yerine işi eşzamanlılığa bırakın: istemci async olduğu için birkaç çözüm üzerinde çalışan bir Task.WhenAll onları yan yana yürütür.

Kısa özet

C# ile Friendly Captcha çözmek için widget script’ini bulun, ondan v1 mi v2 mi olduğuna karar verin ve bu sürümü sitekey ve sayfa URL’siyle birlikte FriendlyCaptchaAsync’e verin. Site alanın adını değiştirmediyse token’ı v1 için frc-captcha-solution, v2 için frc-captcha-response alanına koyun ve bir kez, hemen gönderin. Widget EU endpoint’ini kullanıyorsa ona uyun, çözümlerin milisaniyeler değil saniyeler sürmesini bekleyin ve çağıran kod çözücünün makinesinden ayrıldığı anda Server moduna geçin.

Yeniden denemeyi nasıl kurguladığınızı belirleyen son bir nokta. Bir token reddedilip döndüğünde gerçek çare neredeyse her zaman doğru sürümle baştan çözmektir ve yerel captcha çözücü kullandığınızda bu yeniden deneme, birinin faturasına eklenen yeni bir kalem yerine zaten sahip olduğunuz bir makinede birkaç saniyeye mal olur.