So lösen Sie Cloudflare-Turnstile-Challenge-Seiten in C#

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

Cloudflare Turnstile gibt es in zwei Varianten, und der C#-Code für jede ist unterschiedlich. Ein in ein Formular eingebettetes Widget benötigt nichts weiter als einen Sitekey und eine URL. Eine seitenfüllende Interstitial-Challenge benötigt zwei zusätzliche Werte, die aus der Seite ausgelesen werden, und sie wird nur akzeptiert, wenn Sie den vom Löser verwendeten User-Agent zurücksenden. Lassen Sie diesen letzten Teil weg, erhalten Sie einen Token, der perfekt aussieht und jedes Mal an der Validierung scheitert.

Diese Anleitung behandelt beides, mit funktionierendem .NET-Code.

Widget oder Challenge-Seite?

Finden Sie heraus, welches Sie vor sich haben, bevor Sie Code schreiben.

Widget-ModusChallenge-Seite
Was Sie sehenEin Kontrollkästchen in einem Formular, mit dem Sie weiterhin interagieren könnenEin seitenfüllendes Interstitial, meist “Checking your browser”
Rest der SeiteLädt normalBlockiert, bis die Challenge gelöst ist
Benötigt data / pagedataNeinJa
Benötigt den zurückgegebenen User-AgentNeinJa

Wenn Sie unsicher sind, unser Live-Turnstile-Demoseite führt die Widget-Variante aus, sodass Sie sie mit dem vergleichen können, was Sie tatsächlich ansteuern.

Einrichtung

CapSkip läuft auf Ihrer eigenen Maschine, es gibt also einen lokalen Dienst, den Sie starten müssen, bevor irgendetwas davon funktioniert. Installieren Sie das SDK von NuGet:

# .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

Richten Sie den Client dann auf den in der CapSkip-App angezeigten Port:

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

Widget-Modus, der einfache Fall

Zwei Argumente, und Sie sind fertig:

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

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

Ablegen result.Code in das cf-turnstile-response Feld und senden Sie das Formular ab. Mehr ist nicht zu tun.

Challenge-Seiten benötigen zwei weitere Werte

Eine Interstitial-Challenge trägt einen anfragebezogenen Zustand, an den der Token gebunden ist. Zwei Teile davon müssen mit Ihrer Lösungsanfrage mitgesendet werden:

  • cData, übergeben als data
  • chlPageData, übergeben als pagedata

Beide sind in der Challenge-Seite selbst eingebettet und nicht in einem Formularattribut, daher müssen Sie die Seite auslesen, bevor Sie sie lösen können. Auf einer Standard-Cloudflare-Zwischenseite werden sie im seiteneigenen challenge-options-Objekt neben dem sitekey offengelegt.

Sie sind ebenfalls zur einmaligen Verwendung und an genau diesen Seitenaufruf gebunden. Rufen Sie sie ab, lösen Sie sofort und behalten Sie sie nicht im Cache zwischen den Versuchen.

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

Der Teil, den jeder übersieht: der User Agent

Turnstile bindet das Token an den Browser-Fingerprint, der es erzeugt hat, und der User-Agent ist Teil davon. CapSkip gibt den zurück, den es verwendet hat, in result.UserAgent. Wenn Sie den Token dann von einem HttpClient seinen eigenen Standard-User-Agent sendet, stimmen die Werte nicht überein, und Cloudflare weist ein Token zurück, das ansonsten völlig gültig ist.

UserAgent wird nur für Turnstile befüllt. Für jeden anderen Captcha-Typ ist es null, weshalb dies Menschen stolpern lässt, wenn sie einen funktionierenden reCAPTCHA-Helfer wiederverwenden.

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);

Wenn Ihr Token abgelehnt wird und Sie einen abgelaufenen cData, ist dies fast immer der Grund.

Fehler richtig behandeln

Jede SDK-Ausnahme leitet sich ab von CapSkipError, sodass Sie diesen einen Typ abfangen oder jeden einzeln behandeln können. Es gibt eine .NET-spezifische Falle, die man kennen sollte.

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 und ValidationException existieren in beiden System und CapSkip. Mit beiden importierten Namespaces wird ein nicht qualifizierter catch (TimeoutException) verweist auf die System eine und wird still niemals ausgelöst. Qualifizieren Sie sie wie oben, oder fangen Sie einfach CapSkipError und untersuchen Sie es.

Mehrere gleichzeitig lösen

Jede Methode liefert einen Task, sodass gewöhnliche .NET-Nebenläufigkeit gilt:

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);
}

Das SDK exportiert außerdem AsyncCapSkip, aber in .NET ist es nur ein Alias von CapSkipClient. Es existiert, damit aus dem Python SDK portierter Code weiter kompiliert. Der Wechsel dazu bringt Ihnen nichts, da .NET-I/O bereits asynchron ist.

Routing über einen Proxy

Wenn die Challenge geosensibel ist, lösen Sie über denselben Netzwerkpfad, von dem aus Sie übermitteln werden:

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

Proxys werden für Turnstile, reCAPTCHA und GeeTest unterstützt. Für Bild-Captchas werden sie nicht unterstützt, da diese aus den Bild-Bytes gelöst werden und die Zielseite niemals berühren.

Häufig gestellte Fragen

Benötige ich immer cData und chlPageData?

Nein. Nur für ganzseitige Interstitial-Herausforderungen. Ein Turnstile-Widget innerhalb eines Formulars benötigt nichts weiter als den sitekey und die Seiten-URL, und das Übergeben leerer Werte an ein Widget lässt die Lösung eher scheitern, als dass es hilft.

Mein Token ist gültig, aber die Website lehnt ihn trotzdem ab. Warum?

Fast immer der User Agent. Turnstile bindet den Token an den Fingerprint, der ihn erzeugt hat, sodass Sie mit dem Wert übermitteln müssen, der in result.UserAgent. Die zweithäufigste Ursache ist eine veraltete cData, die an einen einzelnen Seitenaufruf gebunden ist.

Funktioniert das mit .NET Framework?

Ja. Das Paket zielt auf .NET Standard 2.0 ab, es läuft also auf .NET Framework 4.6.1 und neuer, .NET Core 2.0+ und jeder modernen .NET-Version. Aus synchronem Code können Sie aufrufen .GetAwaiter().GetResult(), wobei ordentliches await besser ist.

Wie lange sollte eine Turnstile-Lösung dauern?

Normalerweise ein paar Sekunden. Der Client fragt intern ab, beginnend bei 250 ms und dann zurückgehend auf pollingInterval, und gibt auf bei recaptchaTimeout der standardmäßig 300 Sekunden beträgt. Wenn Sie diese Obergrenze ständig erreichen, prüfen Sie, ob der CapSkip-Dienst tatsächlich läuft, anstatt die Zeitüberschreitung zu erhöhen.

Zusammenfassung

Widget-Turnstile ist ein Aufruf mit zwei Argumenten. Challenge-Seiten benötigen data und pagedata frisch von der Seite gelesen, und das Token muss mit dem User-Agent übermittelt werden, der zusammen damit zurückgegeben wird. Fangen Sie CapSkipError statt gegen die Namespace-Kollision anzukämpfen, und verwenden Sie einen Proxy, wenn die Challenge geo-sensibel ist.

Die vollständige Methodenoberfläche für .NET finden Sie auf der C#-Captcha-Löser Seite, die Parameterreferenz finden Sie in der API-Dokumentation, und Turnstile-Unterstützung deckt die anderen Sprachen ab. CapSkip selbst ist ein unbegrenzter Captcha-Löser das lokal läuft, sodass nichts davon Kosten pro Lösung verursacht.