Node.js ile AWS WAF Widget CAPTCHA Nasıl Çözülür

Bir widget sayfasında Node.js ile AWS WAF CAPTCHA’sını çözmek için widget’ın apiKey değerini ve jsapi.js adresini sayfadan okuyup bunları CapSkip AWS WAF çözücüsü üzerinden amazonWaf ile gönderip, döndürdüğü voucher çiftini bir token ile takas edip o token’ı bir sonraki isteğinizle gönderirsiniz. Widget, AWS WAF tarafından kullanılan ikinci biçimdir. Bulmacayı bir form ya da giriş sayfası kendisi çizer, bu yüzden ne bir HTTP 405 sayfası ne de okunacak bir gokuProps vardır. Bu rehber, bütün döngüyü CapSkip Node.js SDK ve Node.js ile gelen fetch ile yapar. 405 sayfasının kendi rehberi şudur: Python kılavuzu.
Neye ihtiyacınız var
- Bir Windows bilgisayarında çalışan CapSkip 3.0.0 veya üzeri. Bu sürümle AWS WAF çözme desteği geldi. İlk başlatmayı kurulum kılavuzu adım adım anlatır.
- Node.js 18 veya üzeri (paketin istediği sürüm budur) ve capskip paketinin 1.4.0 veya üzeri sürümü. Daha eski sürümlerde amazonWaf metodu yoktur. Aşağıdaki kod, capskip 1.4.0 ile Node.js 24.22.0 üzerinde çalıştı. Burada başka bir Node.js sürümü denenmedi.
- Bir PowerShell istemi. Komutlar PowerShell sözdizimini kullanır.
- Sahibi olduğunuz ya da otomatikleştirmenize izin verilen, üzerinde bir AWS WAF CAPTCHA widget’ı bulunan bir sayfa ve onu bir kez incelemek için geliştirici araçları olan bir tarayıcı.
- Çözücü için bir adres. Local modunda CapSkip 127.0.0.1 üzerinden yalnızca o cihaza yanıt verir. Server modunda ağ adresinizi veya genel IP’nizi dinler, böylece başka bir bilgisayardaki, bir VPS’teki veya barındırılan bir platformdaki script API üzerinden ona erişebilir. İkisi de şurada ayarlanır: bağlantı ayarları.
Nasıl test edildi: kod, gerçek bir AWS WAF sitesine karşı değil, benim yazdığım üç sahte (mock) sunucuya karşı çalıştırıldı. Birincisi AWS WAF denetimlerini, CapSkip API belgeleri içinde listelendiği gibi kopyalar; ikincisi iletişim sayfasında bir widget bulunan bir sitenin, üçüncüsü AWS’nin token sunucusunun yerini tutar. SDK, gerçek capskip 1.4.0 idi. Bu kod gerçek CapSkip uygulamasına karşı çalıştırılmadı ve hiçbir canlı AWS WAF sitesi kullanılmadı; bu yüzden aşağıdaki hiçbir sayı bir çözüm süresi değildir ve belirli bir canlı sitenin bu akışın ürettiği token’ı kabul edeceğini söyleyemem.
1. Adım: projeyi kurun ve widget değerlerini bulun
Bir klasör oluşturun, bir proje başlatın ve capskip’i kurun:
npm init -y npm install capskip
Bir widget sayfası jsapi.js adlı bir script yükler ve bir seçenekler nesnesiyle AwsWafCaptcha.renderCaptcha çağrısı yapar. AWS WAF belgeleri bu nesnedeki apiKey değerinin, widget’ı kullanmasına izin verilen istemci alan adlarını listeleyen şifreli bir anahtar olduğunu söyler; yani değer tek bir siteye aittir. CapSkip sayfadan iki şeye ihtiyaç duyar: sitekey olarak adlandırdığı apiKey değeri ve jsapi.js adresinin tamamı. Bir widget sayfasında gokuProps yoktur, bu yüzden iv ve context göndermezsiniz. jsapi.js adresini bunlar olmadan göndermek, isteği bir widget çözümü olarak işaretler.
İlk blok her ikisini de sayfanın HTML’inden okur. Bazı siteler apiKey değerini bunun yerine ayrı bir JavaScript bundle’ında tutar. Bu durumda fonksiyon null döndürür ve çözüm, sayfanın yüklediği script’lerde apiKey aramaktır.
'use strict';
const { CapSkip, ApiException } = require('capskip');
const PAGE_URL = 'https://www.example.com/contact'; // the page that draws the widget
// The folder that the page's challenge.js loads from (see the Network tab).
const TOKEN_BASE = 'https://3f2a9c7d41b0.edge.sdk.awswaf.com/3f2a9c7d41b0/8e51d0c7a2f4/';
async function readWidget() {
const res = await fetch(PAGE_URL, { headers: { Accept: 'text/html' } });
const html = await res.text();
const src = /<script[^>]+src="([^"]*\/jsapi\.js)"/i.exec(html);
const key = /apiKey\s*:\s*["']([^"']+)["']/.exec(html);
if (!src || !key) return null; // not in the HTML: look in the page's scripts
return { sitekey: key[1], jsapiScript: new URL(src[1], PAGE_URL).href };
}Bir sayfadaki script adresi göreli olabilir ya da iki eğik çizgiyle başlayabilir, bu yüzden fonksiyon onu sayfa URL’siyle tam bir adrese çevirir. Bloğun üstüne yakın TOKEN_BASE, elle doldurduğunuz bir sabittir ve nedenini sonraki adım açıklar.
2. Adım: token sunucusunu bir kez bulun
Voucher çifti, AWS’nin kendi sunucusunda bir token ile takas edilir. Bir widget sayfasında bu sunucu, çektiğiniz HTML’de yer almaz. Sayfayı bir tarayıcıda açın, Network sekmesini açın, yeniden yükleyin ve jsapi.js tarafından sizin için yapılan challenge.js isteğini bulun. Kopyalanacak olan, sonu eğik çizgiyle biten klasörüdür. CapSkip belgeleri challenge.js yerine voucher yazmanızı söyler; sonraki adımdaki kod TOKEN_BASE ile bunu yapar.
Bu, site başına tek seferlik bir aramadır, bu yüzden onu yapılandırmanızda tutun. Gerçek bir sitede aynı kalma süresini söyleyemem. Sonraki adımdaki takas başarısız olmaya başlarsa başka bir şeyden şüphelenmeden önce Network sekmesine yeniden bakın.
3. Adım: çözün ve voucher’ı takas edin
SDK metodunun adı amazonWaf. Yalnızca sitekey ve sayfa URL’si zorunludur; seçenekler jsapi.js adresini taşır. Script adresi bir awswaf.com sunucusundaki https adresi olmalıdır ve SDK, başka her şeyi bir istek gönderilmeden önce reddeder. Yanıt, captcha_voucher ve existing_token içeren bir nesnedir; ham yanıt code altında, görev numarası ise captchaId altında bulunur. Metot, reCAPTCHA’nın kullandığı daha uzun 300 saniyelik zaman aşımıyla bekler, çünkü CapSkip bulmacayı gerçek bir tarayıcıda çözer. Süresini ölçmedim.
Takas, çiftin JSON gövde olarak verildiği, voucher endpoint’ine yapılan bir POST isteğidir. CapSkip belgeleri onu, siteyle eşleşen bir Origin başlığıyla birlikte text/plain olarak gönderir. CapSkip uygulamasının kendi kodu ayrıca bir Referer gönderir, bu yüzden kod ikisini de gönderir. Node.js’in fetch’i, bir tarayıcının izin vermeyeceği Origin ayarını yapmanıza izin verir. SDK belgeleri çiftin kısa ömürlü olduğunu söyler, bu yüzden hemen takas edin ve asla saklamayın.
// Local mode. In Server mode, use your server's address instead.
const solver = new CapSkip({ host: '127.0.0.1', port: 8080 });
async function getToken(widget) {
// The answer is a voucher pair, not a token.
const result = await solver.amazonWaf(widget.sitekey, PAGE_URL, {
jsapiScript: widget.jsapiScript,
});
const reply = await fetch(new URL('voucher', TOKEN_BASE), {
method: 'POST',
headers: {
'Content-Type': 'text/plain;charset=UTF-8',
Origin: new URL(PAGE_URL).origin,
Referer: new URL(PAGE_URL).origin + '/',
},
body: JSON.stringify({
captcha_voucher: result.captcha_voucher,
existing_token: result.existing_token,
}),
});
if (!reply.ok) throw new Error(`voucher exchange failed: HTTP ${reply.status}`);
return (await reply.json()).token; // the aws-waf-token value
}Çözümü bir proxy üzerinden göndermek için çağrıya bir proxy seçeneği ekleyin: type değeri HTTP, uri değeri user:[email protected]:8080 olan bir nesne. Mock çalıştırmasında bu, in.php’ye bir proxy ve bir proxytype olarak ulaştı. Test için tek bir adres yeterlidir, ama AWS WAF arkasındaki siteler CAPTCHA’yı çoğu zaman hız sınırlarıyla birlikte kullanır; bu yüzden tek bir adresten sürekli çözüm akışı daha sert bir muamele görür. API belgeleri token belirli bir ağdan gelmek zorundaysa CapSkip ayarlarında bir proxy listesi ya da çağrı başına bir proxy önerir. CapSkip’in kendi çözücüsü sayfa yüklemelerini, bulmacayı ve voucher takasını tek bir proxy üzerinden gönderir, bu yüzden AWS tek bir adres görür. Çözüme bir proxy veriyorsanız kendi isteklerinizi de aynı proxy üzerinden gönderin. Bu kısmı test edemedim.
4. Adım: token’ı sayfanın yaptığı gibi gönderin
Bir widget sayfasında token, sayfanın kendi onSuccess callback’inin aldığıyla aynıdır. Sayfalar onu nasıl ilettikleri bakımından farklılaşır. Çoğu onu aws-waf-token çerezi olarak, bazıları ise x-aws-waf-token başlığı olarak gönderir; bu yüzden Network sekmesi açıkken formu elle bir kez gönderin ve sayfanın isteğinin taşıdığını kopyalayın. Aşağıdaki fonksiyon çerezi gönderir ve başlığı alternatif olarak gösterir. Form alanları sizinkiler için yer tutuculardır.
function submitForm(token) {
return fetch(PAGE_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Cookie: `aws-waf-token=${token}`, // or 'x-aws-waf-token': token
},
body: new URLSearchParams({ email: '[email protected]', message: 'Hello' }),
});
}5. Adım: tam çalışan örnek
Son blok, parçaları yeniden deneme ve giriş noktasıyla birlikte Node.js ile tam bir AWS WAF CAPTCHA çözücüsüne dönüştürür. Dört kod bloğunun hepsini tek bir dosyaya, art arda kaydedin ve node ile çalıştırın. Başarısız bir bulmaca ApiException fırlatır ve döngü yeniden dener; bu her seferinde yeni bir bulmaca getirir. Diğer her hata fırlatılır, bu yüzden yanlış bir host ya da reddedilen bir takas sessizce yeniden denenmez.
async function main() {
const widget = await readWidget();
if (!widget) throw new Error('no jsapi.js script or apiKey in the page HTML');
for (let attempt = 1; attempt <= 3; attempt++) {
try {
const token = await getToken(widget); // exchange at once, never store it
const res = await submitForm(token);
console.log(res.status, await res.text());
return;
} catch (err) {
if (!(err instanceof ApiException)) throw err;
console.log(`attempt ${attempt}: ${err.message}`); // each retry draws a new puzzle
}
}
throw new Error('AWS WAF CAPTCHA not solved in 3 attempts');
}
main().catch((err) => {
console.error(`${err.constructor.name}: ${err.message}`);
process.exitCode = 1;
});Mock çalıştırmasında script şöyle davrandı:
| Mock ayarı | Script ne yaptı |
|---|---|
| Her bulmaca yanıtlandı | Bir görev, bir voucher takası, ardından 200 durumu ve Message sent metni |
| İlk iki bulmaca reddedildi | İki deneme satırı, ardından üçüncü görevde 200 durumu |
| İlk üç bulmaca reddedildi | Üç deneme satırı, ardından hata satırı ve çıkış kodu 1 |
Token, sitenin bağışıklık süresi boyunca çalışır. AWS varsayılan olarak 300 saniye ayarlar ve site sahibinin 60 saniyeden üç güne kadar seçim yapmasına izin verir; bunu AWS WAF belgeleri açıklar. Çok sayıda istek gönderiyorsanız her istek için bir kez çözmek yerine token’ı saklayın ve süresi dolana kadar yeniden kullanın.
Yaygın hatalar
| Hata | Neden | Düzeltme |
|---|---|---|
| no jsapi.js script or apiKey in the page HTML | Sayfa widget’ı bir bundle’dan oluşturur, bu yüzden HTML bu değerleri içermez | Yüklenen script’lerde apiKey ve jsapi.js arayın, sonra değerleri elle geçirin |
| ValidationException | context olmadan iv ya da bir awswaf.com sunucusunda tam bir https adresi olmayan bir script adresi | Bir widget için iv ya da context göndermeyin ve jsapi.js adresini sayfadaki hâliyle aynen kopyalayın |
| ERROR_CAPTCHA_UNSOLVABLE içeren ApiException | Bulmaca yanıtlanamadı | Yeniden gönderin. API belgeleri her denemenin yeni bir bulmaca getirdiğini belirtir |
| ERROR_TASK_NOT_SUPPORTED | API belgeleri bunu, CapSkip’te kapatılmış bir görev türü için listeler | CapSkip uygulamasındaki AWS WAF ayarlarını kontrol edin |
| ERROR_PROXY_FORMAT | Proxy dizesi ayrıştırılamadı | user:pass@ip:port kullanın |
| ERROR_NO_SLOT_AVAILABLE | API anahtarının bir istek hız sınırı var ve onu aştınız | Birkaç saniye bekleyin ve yeniden gönderin |
| NetworkException | CapSkip çalışmıyor ya da host veya port yanlış | CapSkip’i başlatın ve bağlantı ayarlarını kontrol edin |
| voucher exchange failed: HTTP 4xx | Büyük olasılıkla eskimiş ya da eşleşmeyen bir çift ya da yanlış TOKEN_BASE. CapSkip uygulamasının kodu, geçersiz bir existing_token için AWS’den HTTP 400 bekler. Bunu gerçek AWS’ye karşı yeniden üretemedim | Hemen takas edin, Network sekmesindeki klasörü kontrol edin ve yeni bir görev gönderin |
| Form gönderimi hâlâ reddediliyor | Token’ın süresi doldu ya da sayfa onu bir başlıkta geçiriyor ve siz çerez gönderdiniz | Sayfanın kendi isteğinin taşıdığını kopyalayın |
Çözücüyü bir sunucuda çalıştırmak
Script’in CapSkip’ten iki şeye ihtiyacı var: bir host ve bir port. Local modunda bunlar 127.0.0.1 ve kendi bilgisayarınızdır. Server modunda CapSkip ağ adresinizi veya genel bir IP’yi dinler, böylece başka bir bilgisayardaki, bir VPS’teki veya barındırılan bir platformdaki script aynı API üzerinden ona erişebilir. Host ve port değerlerini CapSkip constructor’ında değiştirin; koddaki başka hiçbir şey değişmez. Kararlı uzaktan erişim için statik bir genel IP önerilir. Server modu da kendi donanımınızda çalışır ve çözüm başına ücretlendirme yoktur. Yine de portu her adrese açar, bu yüzden ulaşmaması gereken adresler için bir Windows Firewall engelleme kuralı ekleyin. Modlar arasında nasıl geçileceğini bağlantı ayarları bölümünde bulabilirsiniz.
FAQ
Bir widget sayfasını 405 challenge sayfasından nasıl ayırt ederim?
Bir challenge sayfası isteğe HTTP 405 ile yanıt verir ve gokuProps tanımlar. Bir widget sayfası, jsapi.js yükleyen ve renderCaptcha çağıran, genellikle bir form üzerinde bulunan sıradan bir sayfadır. Her ikisini de aynı amazonWaf metodu ele alır, yalnızca değerler farklıdır.
Node.js’te bir AWS WAF CAPTCHA’sını tarayıcı olmadan çözebilir miyim?
Script’inizin tarayıcıya ihtiyacı yoktur. CapSkip’e ve siteye düz HTTP istekleri gönderir; CapSkip ise SDK belgelerinin anlattığı gibi bulmacayı, çalıştığı makinedeki gerçek bir tarayıcıda çözer. Bir tarayıcıyı yalnızca bir kez, değerleri sayfadan okumak için kendiniz açarsınız.
SDK, token’ı doğrudan döndürür mü?
Hayır. captcha_voucher ve existing_token döndürür; bunları voucher endpoint’inde takas edersiniz. JSON createTask API’si AWS WAF için de çalışır ve biçimlerinden birkaçı token’ı doğrudan döndürür. Bu biçimleri API belgeleri listeler.
Barındırılan bir platform bunu benim CapSkip’ime karşı çalıştırabilir mi?
Evet, Server modu ile. CapSkip’i ağınızı veya genel IP’nizi dinleyecek şekilde ayarlayın, CapSkip constructor’ını o host ve port bilgisine yöneltin; döngü tek bir bilgisayardakiyle aynı çalışır. Çözücü sizin donanımınızda kalır.
Kısa özet
Node.js’te bir AWS WAF CAPTCHA’sı, bir widget üzerinde 405 sayfasındakiyle aynı bulmacadır, yalnızca yeri farklıdır: apiKey değerini ve jsapi.js adresini okuyun, amazonWaf metodunu çağırın, çifti voucher endpoint’inde takas edin ve token’ı sayfanın yaptığı gibi gönderin. CapSkip, kendi makinenizde çalışan bir captcha atlatma aracıdır; bu yüzden yanıtlayamadığı bir bulmaca size bir ücrete değil, yalnızca bir yeniden denemeye mal olur. SDK’nın geri kalanı için şuraya göz atın: Node.js CAPTCHA çözücü sayfasına.
