So lösen Sie ALTCHA in C# und senden den Token unverändert zurück

Um ALTCHA in C# zu lösen, gibt es nichts abzulesen. ALTCHA ist Proof of Work, keine Erkennung: Die Website gibt eine Challenge heraus, und der Client muss die Zahl per Brute Force finden, die sie erfüllt. Es sind kein Bild, kein Audio und kein Raten beteiligt, was das Lösen deterministisch und schnell macht. Entweder wird die Antwort gefunden, oder die Challenge war fehlerhaft oder bereits abgelaufen. CapSkip hat ALTCHA in Version 1.2.6 hinzugefügt, und das .NET SDK stellt es als eine Methode bereit, die die Seiten-URL plus die Challenge annimmt. Woran die meisten tatsächlich scheitern, ist das, was danach passiert: Der Token muss genau so in das Formular zurück, wie der Solver ihn zurückgegeben hat.
Was Sie brauchen
- CapSkip 1.2.6 oder neuer auf einem Windows-Rechner. Die ALTCHA-Unterstützung kam mit diesem Release.
- Das CapSkip .NET-Paket, das auf .NET Standard 2.0 zielt, also .NET Framework 4.6.1 und höher, .NET Core 2.0 und höher sowie .NET 6 und neuer.
- Die URL der Seite, auf der das Widget sitzt, sowie der Endpunkt, von dem dieses Widget seine Challenge abruft.
- Eine Adresse für den Solver. Der Local-Modus antwortet auf 127.0.0.1 nur für dieses Gerät; der Server-Modus lauscht auf Ihrer Netzwerkadresse oder öffentlichen IP, damit ein anderer Rechner ihn erreichen kann. Schritt 4 erklärt, welcher davon der richtige ist, und beide finden Sie unter Verbindungseinstellungen.
# dotnet add package CapSkip dotnet add package CapSkip
Schritt 1: Den Endpunkt finden, den das ALTCHA-Widget aufruft
Alles andere hängt von diesem einen Wert ab, besorgen Sie ihn sich also zuerst. Öffnen Sie die DevTools, wechseln Sie auf den Tab Network und laden Sie die Seite neu, auf der das Widget sitzt. Das Widget stellt eine Anfrage für seine Challenge, meist an einen Pfad, der altcha enthält. Diese Anfrage-URL ist das, was Sie an den Solver übergeben, und das JSON, das dieser Endpunkt zurückgibt, ist das Challenge-Dokument selbst, das Sie anstelle der URL übergeben können.
Raten Sie nicht, welches Attribut sie benennt, denn das hat sich zwischen den Widget-Generationen geändert. Lesen Sie den Seitenquelltext.
| Widget-Generation | Attribut, das die Challenge benennt |
|---|---|
| v1 und v2 | challengeurl für einen Endpunkt, mit einem separaten Attribut challengejson für eine Inline-Challenge |
| v3 und neuer | challenge, und dasselbe Attribut nimmt entweder eine URL oder die Challenge-Daten |
Die drei Darstellungsvarianten native, checkbox und switch sind rein optisch. Alle senden dieselbe Payload, und der Unterschied erreicht den Solver nie, Sie müssen also nicht herausfinden, welche davon Sie vor sich haben. ALTCHA behandelt die Widget-Attribute in seiner eigenen Integrationsdokumentation.
Schritt 2: Der Aufruf zum Lösen und die zwei Wege, eine Challenge zu übergeben
Eine Methode, zwei Argumente: die Seiten-URL, dann ein Options-Dictionary, das die Challenge enthält. Geben Sie ihr den Endpunkt, und CapSkip ruft die Challenge für Sie ab.
// dotnet add package CapSkip
using CapSkip;
var solver = new CapSkipClient(host: "127.0.0.1", port: 8080);
// CapSkip fetches the challenge, then brute-forces the counter.
var result = await solver.AltchaAsync(
"https://example.com/signup",
new Dictionary<string, object?>
{
["challenge_url"] = "https://example.com/altcha/challenge",
});
Console.WriteLine(result.Token); // base64 payload for the form field
Console.WriteLine(result.Number); // the counter that satisfied itZwei Felder des Ergebnisses gibt es nur bei ALTCHA. Token ist die base64-Payload, die das Formular erwartet, und Number ist der Zähler, der die Challenge gelöst hat. Die Eigenschaft Code enthält dieselbe Zeichenfolge wie Token, beides funktioniert also, aber Token ist nach dem Feld benannt, in das es gehört, und liest sich an der Aufrufstelle besser. Die GeeTest-Felder und der Turnstile-User-Agent bleiben hier null.
Es lohnt sich, Number zu loggen. Der Wert wird für beide ALTCHA-Generationen gemeldet, obwohl sich ihre Payloads unterscheiden: Ein Legacy-Token trägt den Zähler auf oberster Ebene, ein Proof-of-Work-v2-Token dagegen nicht, es hält ihn stattdessen in einem solution-Objekt. CapSkip liest ihn in seiner eigenen API-Antwort aus dem solution-Objekt aus, und diese Antwort meldet beide Generationen auf dieselbe Weise.
Stattdessen das Challenge-Dokument übergeben
Wenn Ihr Code die Challenge schon abgerufen hat, übergeben Sie das Dokument, und es findet überhaupt keine Netzwerkanfrage statt. Das ist der schnellere Weg, wenn Sie die Seite ohnehin scrapen, und der richtige, wenn die Challenge eingebettet im HTML ankommt und nicht von einem Endpunkt.
// No fetch happens: the document is already here.
var result = await solver.AltchaAsync(
"https://example.com/signup",
new Dictionary<string, object?>
{
["challenge_json"] = new Dictionary<string, object>
{
["algorithm"] = "SHA-256",
["challenge"] = "YOUR_CHALLENGE_HASH",
["salt"] = "YOUR_SALT",
["signature"] = "YOUR_SIGNATURE",
["maxnumber"] = 1000000,
},
});Diese Option nimmt ein Dictionary, das für Sie serialisiert wird, oder einen JSON-String, wenn Sie schon einen haben. Beides zu senden, den Endpunkt und das Dokument, ist erlaubt, und das Inline-Dokument gewinnt, weil ein Abruf nur noch einmal holen würde, was Sie gerade geliefert haben. Die beiden Wege verhalten sich unter Last außerdem unterschiedlich: Eine Inline-Challenge, die bereits abgelaufen ist, wird sofort abgelehnt, statt sinnlos gehasht zu werden, während ein Endpunkt dem Solver erlaubt, eine frische Challenge zu holen, falls die erste gestorben ist, während der Auftrag in der Warteschlange lag.
Welche Algorithmen der Solver abdeckt
Dieselbe Methode bedient beide Generationen. Das Legacy-Verfahren ist mit SHA-1, SHA-256, SHA-384 und SHA-512 abgedeckt, Proof of Work v2 mit PBKDF2 und iterativem SHA. PBKDF2 ist der Standard, den ALTCHA selbst empfiehlt, damit ist also die große Mehrheit der Live-Websites abgedeckt.
Argon2id und scrypt sind die Ausnahmen, und sie werden abgelehnt statt versucht: Ein Task, der eines von beiden nutzt, kommt nach etwa einer Drittelsekunde mit ERROR_CAPTCHA_UNSOLVABLE zurück und wird nie wiederholt. Das ist so gewollt. Eine speicherharte Funktion lässt sich durch einen erneuten Versuch nicht beheben, deshalb ist sofortiges Scheitern besser, als beschäftigt zu wirken. Bei ALTCHA deutet dieses Ergebnis auf den Algorithmus und nicht auf ein unlesbares Bild, und der Fehlercode hat einen eigenen Leitfaden.
Schritt 3: Den Token unverändert zurücksenden, bevor er abläuft
Das Widget sendet seine Payload in einem Formularfeld namens altcha, dort gehört also Ihr Token hin. Das ist der Schritt, der unauffällig kaputtgeht.
// Send it exactly as it came back: no trimming,
// no re-encoding, no reordering.
var body = new FormUrlEncodedContent(new Dictionary<string, string>
{
["email"] = "[email protected]",
["altcha"] = result.Token!,
});
var response = await http.PostAsync("https://example.com/signup", body);Der Token ist base64 eines JSON-Dokuments, dessen Felder von der HMAC-Signatur des Servers abgedeckt werden. Jede Änderung macht ihn ungültig, alles, was nach Aufräumen aussieht, zerstört also das Absenden: Leerzeichen abschneiden, ihn dekodieren und neu kodieren oder das JSON mit den Schlüsseln in anderer Reihenfolge neu aufbauen. Manche Integrationen lesen die Payload aus einem JSON-Body-Feld statt aus einem Formularfeld, prüfen Sie also, was das Absenden der Seite selbst sendet, und machen Sie es genauso.
Die andere Art, wie dieser Schritt scheitert, ist das Timing. Challenge-Fenster sind kurz, manche Websites schließen sie innerhalb von zwei Minuten, und wenn eines abläuft, weist die Website die Antwort mit einem nackten Verifizierungsfehler ab, der genauso aussieht wie eine falsche Antwort. Im Fehler steht nichts, was Ihnen sagt, welcher der beiden Fälle eingetreten ist. Drei Gewohnheiten verhindern das: Rufen Sie die Challenge unmittelbar vor dem Lösen ab und nicht am Anfang eines langen Durchlaufs, senden Sie den Token in derselben Arbeitseinheit ab, die ihn gelöst hat, und halten Sie niemals einen Token, während ein Mensch ein Formular ausfüllt.
Die Polling-Timeouts des Clients sind hier nicht das, was Sie begrenzt, denn beide sind weit länger als dieses Zwei-Minuten-Fenster. ALTCHA ist CPU-Arbeit und keine Browser-Sitzung, es läuft also auf dem Standard-Polling-Timeout und nicht auf dem längeren für reCAPTCHA.
| Konstruktor-Option | Standard | Was sie abdeckt |
|---|---|---|
| defaultTimeout | 120 Sekunden | Polling für ALTCHA und Bild-Captchas |
| recaptchaTimeout | 300 Sekunden | Polling für reCAPTCHA, Turnstile und GeeTest |
| pollingInterval | Maximal 5 Sekunden | Das Polling beginnt bei 0,25 Sekunden und steigt per Backoff bis auf diesen Wert |
Schritt 4: Wo der Solver läuft und welchen Verbindungsmodus das erfordert
Die Beispiele oben verwenden 127.0.0.1, weil das richtig ist, wenn Ihr Code und der Solver auf demselben Rechner liegen. Sobald der Code, der den Solver aufruft, woanders läuft, etwa in einem Container, auf einem Build-Agent, einem VPS oder bei einem Managed-Host, zeigt Loopback nicht mehr auf den Solver, und der erste Lösungsversuch wirft eine NetworkException.
Schalten Sie CapSkip in den Server-Modus, dann lauscht er stattdessen auf Ihrer Netzwerkadresse oder öffentlichen IP, sodass jede dieser Umgebungen ihn über die API erreichen kann. Eine statische öffentliche IP ist empfehlenswert, wenn der Weg über das Internet geht, zusammen mit einer Firewall-Regel, die nur die erwarteten Adressen zulässt. Der Server-Modus ändert nur, wo der Solver lauscht, und sonst nichts: Es bleibt Ihre Hardware, und es bleibt ohne Abrechnung pro Lösung. Lesen Sie den Host aus einer Umgebungsvariable, damit ein Build an beiden Orten funktioniert. Der Client liest CAPSKIP_HOST nicht von sich aus, übergeben Sie den Wert also an den Konstruktor, wie es das vollständige Beispiel unten tut.
| Wo der C#-Code läuft | Welcher Verbindungsmodus |
|---|---|
| Auf dem CapSkip-Rechner, in einer IDE oder einer Konsolenanwendung | Local-Modus. 127.0.0.1 ist hier wirklich richtig |
| Auf einem anderen Rechner im selben Netzwerk | Server-Modus, auf der privaten Adresse dieses Rechners |
| Auf einem Container-Host, VPS oder einer Managed-Plattform | Server-Modus mit einer statischen öffentlichen IP und einer Firewallregel |
Ein ALTCHA-spezifischer Hinweis zu Proxys. Ein Proxy wird hier unterstützt, aber nur für den Abruf der Challenge verwendet. Es gibt keine Browser-Sitzung, die geroutet werden müsste, er hat also keinen Einfluss auf den Proof of Work selbst.
Vollständiges lauffähiges Beispiel
// dotnet add package CapSkip
using CapSkip;
var http = new HttpClient();
var solver = new CapSkipClient(
host: Environment.GetEnvironmentVariable("CAPSKIP_HOST") ?? "127.0.0.1",
port: 8080);
try
{
var result = await solver.AltchaAsync(
"https://example.com/signup",
new Dictionary<string, object?>
{
["challenge_url"] = "https://example.com/altcha/challenge",
});
// Submit here, while the challenge is still fresh.
var body = new FormUrlEncodedContent(new Dictionary<string, string>
{
["email"] = "[email protected]",
["altcha"] = result.Token!,
});
var response = await http.PostAsync("https://example.com/signup", body);
Console.WriteLine($"{(int)response.StatusCode} after counter {result.Number}");
}
catch (ApiException ex)
{
// ERROR_CAPTCHA_UNSOLVABLE here means Argon2id or scrypt.
Console.WriteLine($"refused: {ex.Message}");
}
catch (CapSkip.TimeoutException)
{
Console.WriteLine("gave up waiting; defaultTimeout is 120 seconds");
}Die anderen Typen haben dieselbe Form mit einer anderen Methode. RecaptchaAsync nimmt einen sitekey und eine Seiten-URL, TurnstileAsync und GeetestAsync funktionieren genauso, und das Lösen von Bildern ist ein base64-Aufruf. Die vollständige Methodenliste finden Sie auf der C#-Captcha-Solver-Seite.
Turnstile auf Challenge-Seiten ist der eine Typ, der mehr als einen sitekey braucht. Seine zusätzlichen Werte behandelt der C#-Leitfaden zu Challenge-Seiten.
Häufige Fehler und was sie bedeuten
| Was Sie sehen | Ursache | Beheben |
|---|---|---|
| Ein nackter Verifizierungsfehler von der Website, bei einem Token, der in Ordnung aussieht | Die Challenge ist abgelaufen, bevor das Formular abgesendet wurde | Abrufen, lösen und absenden in einer Arbeitseinheit |
| ERROR_CAPTCHA_UNSOLVABLE in einer ApiException, nach etwa einer Drittelsekunde | Die Challenge verwendet Argon2id oder scrypt | Nichts zu wiederholen. Diese beiden werden bewusst abgelehnt |
| Eine ValidationException beim Aufruf | Keine der beiden Challenge-Optionen wurde übergeben, oder es wurde eine Option übergeben, die ALTCHA nicht annimmt | Übergeben Sie den Challenge-Endpunkt oder das Challenge-Dokument und lassen Sie alles andere weg |
| Eine NetworkException beim ersten Lösen | CapSkip läuft nicht, oder Host und Port sind falsch | Starten Sie CapSkip und prüfen Sie dann, ob es im Local-Modus oder im Server-Modus laufen soll |
| Die Eigenschaft Token im Ergebnis ist null | Token wird nur bei ALTCHA gefüllt | Rufen Sie AltchaAsync auf. Bei einem ALTCHA-Ergebnis enthält die Eigenschaft Code dieselbe Zeichenfolge |
| Der Build scheitert an einer mehrdeutigen TimeoutException | CapSkip und System definieren beide diesen Kurznamen | Schreiben Sie CapSkip.TimeoutException vollständig aus oder fangen Sie CapSkipError |
| Das Formular weist einen Token ab, den Ihre Logs als gelöst ausweisen | Irgendetwas hat die Payload neu kodiert, beschnitten oder umsortiert | Geben Sie die Zeichenfolge unverändert direkt weiter |
FAQ
Braucht man zum Lösen von ALTCHA in C# einen Browser?
Nein, und genau das ist das Praktische daran. ALTCHA gibt ein Hashing-Problem heraus und nicht etwas zum Anschauen, die Arbeit ist also reine CPU-Arbeit und in Millisekunden fertig. Sie brauchen keinen WebDriver, kein Headless-Chrome und keinen User-Agent. Eine Konsolenanwendung mit einem HttpClient genügt, was auch bedeutet, dass es problemlos in einem Worker-Service, einem Queue-Consumer oder einem Build-Schritt läuft, wo das Steuern eines Browsers unpraktisch wäre.
Kann eine .NET-Anwendung auf einer gehosteten Plattform den Solver erreichen?
Ja. Schalten Sie CapSkip in den Verbindungseinstellungen in den Server-Modus, damit er auf einer Netzwerkadresse statt auf Loopback lauscht, und richten Sie dann CAPSKIP_HOST auf diese Adresse. Ein Container-Host, ein VPS, ein CI-Agent oder ein Managed-App-Service verbinden sich alle auf dieselbe Weise, über dieselbe HTTP-API. Verwenden Sie eine statische öffentliche IP, wenn der Weg über das Internet führt, und beschränken Sie sie mit einer Firewall-Regel. Der Solver bleibt in jedem dieser Fälle auf Hardware, die Ihnen gehört, an der Lizenz und der Zahl der Lösungen ändert sich also nichts.
Soll ich den Endpunkt oder das Challenge-Dokument übergeben?
Übergeben Sie den Endpunkt, sofern Sie das Dokument nicht schon haben. Es ist ein Eintrag im Options-Dictionary, es spart Ihnen eine Anfrage, und wenn die Challenge veraltet, während der Auftrag in der Warteschlange steht, holt der Solver von selbst eine frische. Übergeben Sie das Dokument, wenn Ihr Scraper es schon von der Seite gelesen hat, wenn die Challenge im HTML eingebettet ist und nicht von einem Endpunkt ausgeliefert wird, oder wenn der Abruf Cookies oder Header braucht, die Ihr Code hat und der Solver nicht. Im letzten Fall lohnt es sich, die Proxy-Option zu kennen, denn bei ALTCHA gilt sie für den Abruf und nur für den Abruf.
Warum ist mein Zähler jedes Mal eine andere Zahl?
Weil er die Antwort auf genau diese Challenge ist und keine Eigenschaft der Website. Jede Challenge trägt ihren eigenen salt, die Zahl, die sie erfüllt, ändert sich also bei jeder Ausgabe und kann überall bis zu dem maxnumber-Wert liegen, den die Challenge erlaubt. Ein großer Zähler bedeutet einfach, dass mehr Hashing nötig war, was sich in ein paar zusätzlichen Millisekunden zeigt und in nichts anderem. In Logs ist er nützlich als Beleg dafür, dass die Arbeit wirklich getan wurde, und zum Zwischenspeichern ist er unbrauchbar.
Die Kurzfassung
Lesen Sie den Challenge-Endpunkt vom Widget ab, übergeben Sie ihn zusammen mit der Seiten-URL an die eine ALTCHA-Methode und senden Sie den Token unverändert in das Feld namens altcha zurück. Halten Sie Abruf, Lösen und Absenden im selben Block, denn das Challenge-Fenster kann sich innerhalb von zwei Minuten schließen, und eine abgelaufene Challenge sieht genauso aus wie eine falsche Antwort. ERROR_CAPTCHA_UNSOLVABLE ist nur bei Argon2id und scrypt zu erwarten, die rundweg abgelehnt und gar nicht erst versucht werden. Wechseln Sie in den Server-Modus, sobald der aufrufende Code nicht mehr auf demselben Rechner wie der Solver liegt.
- Was die Challenge ist und wie der Typ funktioniert: die ALTCHA-Solver-Seite.
- Alle anderen Methoden, die das .NET-Paket bereitstellt: die C#- und .NET-Solver-Seite.
Noch eine letzte Sache, die verändert, wie Sie Wiederholungen gestalten. Weil ein lokaler Captcha-Löser den Proof of Work auf einem Rechner berechnet, der Ihnen bereits gehört, kostet der erneute Versuch bei einer abgelaufenen Challenge nur ein paar Millisekunden eigener CPU-Zeit und sonst nichts, Sie können sich also erlauben, eine frische Challenge zu holen, statt eine veraltete weiterzuschleppen.
