<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Anti-bot engineering]]></title><description><![CDATA[Anti-bot engineering]]></description><link>https://solvehub.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Thu, 12 Nov 2026 09:51:03 GMT</lastBuildDate><atom:link href="https://solvehub.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Cookie anti-bot: apa itu _abck dan reese84, dan mengapa keduanya cepat kedaluwarsa]]></title><description><![CDATA[Banyak tim sampai di titik yang sama: permintaan pertama berhasil, lalu tiba-tiba balasan berubah menjadi 403 padahal cookie-nya masih ada di jar…]]></description><link>https://solvehub.hashnode.dev/cookie-anti-bot-apa-itu-abck-dan-reese84-dan-mengapa-keduanya-cepat-kedaluwarsa</link><guid isPermaLink="true">https://solvehub.hashnode.dev/cookie-anti-bot-apa-itu-abck-dan-reese84-dan-mengapa-keduanya-cepat-kedaluwarsa</guid><dc:creator><![CDATA[Lsr]]></dc:creator><pubDate>Tue, 10 Nov 2026 04:43:54 GMT</pubDate><content:encoded><![CDATA[<p>Banyak tim sampai di titik yang sama: permintaan pertama berhasil, lalu tiba-tiba balasan berubah menjadi 403 padahal cookie-nya masih ada di jar. Penyebabnya jarang berupa "cookie kurang satu"; lebih sering karena cookie yang dipakai sudah tidak lagi cocok dengan apa yang diharapkan server pada permintaan itu.</p>
<p>Dua cookie yang paling sering jadi sumber kebingungan adalah <code>_abck</code> dari Akamai dan <code>reese84</code> dari Imperva. Keduanya sering disebut "token anti-bot", padahal cara kerjanya berbeda cukup jauh. Kalau salah memahami bedanya, debugging akan berputar di tempat.</p>
<h2>_abck: buku besar yang ditulis ulang setiap respons</h2>
<p><code>_abck</code> bukan nilai tunggal. Isinya beberapa segmen yang dipisah karakter <code>~</code>, dan segmen-segmen itu membawa arti berbeda: ada bagian yang menyimpan penilaian sensor, ada bagian yang menandai apakah sesi dianggap sah, dan ada penghitung yang naik setiap kali server menilai ulang.</p>
<p>Artinya penting: <code>_abck</code> yang valid bukan nilai yang bisa disalin sekali lalu dipakai selamanya. Server Akamai mengirim ulang <code>Set-Cookie</code> pada hampir setiap respons, dan nilai barunya bergantung pada apa yang dikirim klien sebelumnya. Kalau klien menyimpan cookie pertama lalu membekukannya, permintaan berikutnya datang dengan nilai yang lebih tua daripada yang diharapkan server, dan penilaiannya turun.</p>
<p>Pola kegagalan yang paling sering terlihat:</p>
<ul>
<li>Cookie disalin dari sesi lain (browser lain, mesin lain) lalu ditempel ke klien skrip. Nilainya sah secara bentuk, tetapi tidak terikat pada sidik jari sesi yang mengirimnya.</li>
<li>Cookie disimpan, tetapi respons yang membawa pembaruan tidak diproses. Klien mengirim ulang nilai lama berulang kali sampai akhirnya ditantang.</li>
<li>Hanya <code>_abck</code> yang diperhatikan, sementara header dan urutan permintaan yang menjadi konteks penilaian diabaikan.</li>
</ul>
<h2>reese84: token yang umurnya dihitung dalam menit</h2>
<p>Kalau <code>_abck</code> terus dinilai ulang, <code>reese84</code> lebih mirip tiket masuk dengan masa berlaku pendek. Nilainya diterbitkan oleh skrip sensor Imperva, biasanya setelah tantangan diselesaikan, dan umurnya dihitung dalam menit: sering 5 sampai 15 menit, tergantung konfigurasi situs.</p>
<p>Karena itu, pertanyaan kenapa <code>reese84</code> saya ditolak hampir selalu berujung pada satu hal: tokennya sudah kedaluwarsa, atau token itu diterbitkan oleh skrip dengan parameter yang berbeda dari yang dipakai situs target. Token tidak membawa izin; ia hanya bukti bahwa suatu sesi pernah menyelesaikan tantangan tertentu.</p>
<h2>Perbedaan yang menentukan saat debugging</h2>
<table>
<thead>
<tr>
<th>Aspek</th>
<th>_abck (Akamai)</th>
<th>reese84 (Imperva)</th>
</tr>
</thead>
<tbody><tr>
<td>Sumber nilai</td>
<td>Sensor Akamai, ditulis ulang tiap respons</td>
<td>Skrip sensor Imperva, sekali terbit</td>
</tr>
<tr>
<td>Umur</td>
<td>Dinilai ulang terus, tidak ada batas tetap</td>
<td>Umumnya 5-15 menit</td>
</tr>
<tr>
<td>Penanda gagal</td>
<td>Flag pada segmen kedua berubah</td>
<td>Permintaan ditantang ulang</td>
</tr>
<tr>
<td>Kesalahan umum</td>
<td>Menyalin cookie antar-sesi</td>
<td>Memakai token tanpa skrip yang benar</td>
</tr>
</tbody></table>
<h2>Yang perlu diperiksa lebih dulu</h2>
<p>Sebelum menyimpulkan bahwa Anda butuh solver, ada tiga hal yang biasanya lebih murah diperbaiki:</p>
<ol>
<li><strong>Alur cookie.</strong> Pastikan setiap <code>Set-Cookie</code> diproses, termasuk yang datang bersama respons 403. Banyak klien hanya membaca cookie saat status 200.</li>
<li><strong>Konsistensi sidik jari.</strong> User-Agent, header <code>sec-ch-ua</code>, bahasa, dan zona waktu harus konsisten antara permintaan HTML pertama dan permintaan XHR berikutnya.</li>
<li><strong>Waktu tunggu.</strong> Untuk <code>reese84</code>, jeda antar-permintaan yang terlalu panjang membuat token mati sebelum dipakai.</li>
</ol>
<p>Kalau ketiganya sudah benar dan blokir tetap muncul, barulah masuk akal memakai layanan penyelesaian tantangan. Di situ tugasnya berubah: bukan menyalin cookie, tetapi mendapatkan token yang diterbitkan oleh skrip yang tepat, untuk sesi yang tepat.</p>
<h2>Ringkasan</h2>
<p><code>_abck</code> adalah catatan yang terus ditulis ulang server; <code>reese84</code> adalah tiket berumur pendek. Yang pertama gagal karena tidak diperbarui, yang kedua gagal karena kedaluwarsa. Memisahkan dua penyebab ini sendiri sudah menghilangkan sebagian besar waktu debugging.</p>
<hr />
<p><em>Tulisan ini bagian dari seri anti-bot engineering. Glosarium lengkap dalam Bahasa Indonesia ada di <a href="https://seencxy.github.io/id/glossary/">Glosarium cookie anti-bot</a>, dengan halaman terpisah untuk <a href="https://seencxy.github.io/id/glossary/akamai-abck/">_abck</a> dan <a href="https://seencxy.github.io/id/glossary/reese84/">reese84</a>. Penulis adalah pengelola <a href="https://www.tiam.codes/">SolveHub</a>, API penyelesaian CAPTCHA dan tantangan anti-bot untuk pengujian yang diizinkan; dokumentasi terkait ada di <a href="https://www.tiam.codes/docs/akamai">Akamai</a> dan <a href="https://www.tiam.codes/docs/imperva">Imperva</a>.</em></p>
]]></content:encoded></item><item><title><![CDATA[Akamai _abck: the cookie that rewrites itself on every response]]></title><description><![CDATA[Akamai Bot Manager is the one anti-bot product where the cookie is the least interesting part of the story. Everyone fixates on _abck. What actually…]]></description><link>https://solvehub.hashnode.dev/akamai-abck-the-cookie-that-rewrites-itself-on-every-response</link><guid isPermaLink="true">https://solvehub.hashnode.dev/akamai-abck-the-cookie-that-rewrites-itself-on-every-response</guid><category><![CDATA[akamai]]></category><category><![CDATA[web scraping]]></category><category><![CDATA[Python]]></category><category><![CDATA[Security]]></category><dc:creator><![CDATA[Lsr]]></dc:creator><pubDate>Tue, 10 Nov 2026 01:41:07 GMT</pubDate><content:encoded><![CDATA[<p>Akamai Bot Manager is the one anti-bot product where the cookie is the least interesting part of the story. Everyone fixates on <code>_abck</code>. What actually decides whether your next request passes is the sequence of updates <code>_abck</code> went through — and the headers that came back with it.</p>
<p>This post is about three things that break Akamai automation in practice: treating <code>_abck</code> as a one-time token, discarding <code>bm_sz</code> and <code>ak_bmsc</code> because <code>_abck</code> looks like the important one, and ignoring <code>solution.headers</code> because no other solver returns any.</p>
<blockquote>
<p>Scope: everything below is for QA automation on properties you are authorised to test.</p>
</blockquote>
<h2>Three cookies, three jobs</h2>
<p>Akamai hands out cookies in layers, and each one answers a different question.</p>
<ul>
<li><code>ak_bmsc</code> — the anonymous browser session. It is issued before any sensor data runs, it is short-lived, and on its own it gets you a page, not an API.</li>
<li><code>bm_sz</code> — the session marker that pairs with <code>_abck</code>. They are set together and they are checked together. A request carrying a healthy <code>_abck</code> but no matching <code>bm_sz</code> is a very common way to get re-challenged while your logs say "the cookie is fine".</li>
<li><code>_abck</code> — the state carrier. It holds the sensor payload and the verdict on that payload.</li>
</ul>
<p>If you only keep one, keep <code>_abck</code> — but understand that on its own it is half a conversation.</p>
<h2>Reading the verdict inside _abck</h2>
<p>A <code>_abck</code> value is a <code>~</code>-separated blob. Two segments matter more than the rest:</p>
<ul>
<li>A <code>~-1~</code> segment means a sensor post is still expected, or the one that was sent was not accepted.</li>
<li>A <code>~0~</code> segment means the sensor data was accepted and the browser is validated.</li>
</ul>
<p>A long value can contain both markers in different positions, because the value accumulates state. So the check is not "does the cookie contain <del>0</del>": it is which marker comes last, and whether the segment count went up or down since the previous response.</p>
<p>This is also why status codes lie on Akamai more than on any other product. A <code>200 OK</code> with a challenge document in the body and a <code>~-1~</code> cookie is a block. A <code>403</code> is almost the easy case: it is the one failure the status code actually reports.</p>
<h2>The rewrite: why replaying the solve value fails</h2>
<p>Akamai does not issue <code>_abck</code> once. Most responses carry a <code>Set-Cookie</code> that replaces it with a longer value and a different marker. That is the point of the design: the cookie is a record of the session's behaviour, so the server extends it as the session continues.</p>
<p>Concretely, if you solve once, store the cookie, and replay it for the next two hundred requests, you are replaying state one of a conversation the server has already advanced past. It works — until it does not, usually a few requests in, and usually with no signal other than a challenge page.</p>
<p>The fix is mechanical: keep a per-session cookie jar, and update it from every response, not just from the solve. Then verify the marker after each update rather than trusting the status code.</p>
<h2>Headers are part of the credential</h2>
<p>This is where Akamai differs from every other solver integration I maintain. Its solve result includes <code>solution.headers</code> — browser headers to reuse in subsequent requests — and the field is explicitly documented as possibly <code>null</code>.</p>
<p>When it is present, replay it. When it is <code>null</code>, fall back to <code>solution.useragent</code> and keep your own header set consistent with it: same <code>Accept-Language</code>, same <code>sec-ch-ua</code> family, same header order. A UA that says Chrome 131 with a <code>sec-ch-ua</code> for Chrome 108 is exactly the sort of mismatch the sensor data is built to catch.</p>
<h2>When the marker never flips: task.ApiURL</h2>
<p>Some Akamai-protected applications only validate the session after a specific XHR or POST — the price lookup, the search call, the cart estimate. Until that request happens inside the session, <code>_abck</code> stays at <code>~-1~</code> no matter how clean the browser is.</p>
<p>For that case the task takes an <code>ApiURL</code> field: the POST target to request within the browser session. The response body is not returned as part of the solve result — you are not scraping that call, you are using it to make the session real. If you are getting valid-looking cookies that are still rejected, a missing <code>ApiURL</code> is the first thing I would check.</p>
<h2>The loop, correctly shaped</h2>
<pre><code class="language-python">import os, requests, time

BASE = os.environ["SOLVEHUB_URL"].rstrip("/")
H = {"Authorization": f"Bearer {os.environ['SOLVEHUB_API_KEY']}"}

payload = {
    "type": "akamai",
    "task": {
        "websiteURL": "https://example.com/product/42",
        "ApiURL": "https://example.com/api/price?sku=42",  # optional but often decisive
        "proxyType": "http",
        "proxyAddress": "203.0.113.10",
        "proxyPort": "8080",
    },
}
task_id = requests.post(f"{BASE}/v1/tasks", headers=H, json=payload, timeout=30).json()["taskId"]

while True:
    t = requests.get(f"{BASE}/v1/tasks/{task_id}", headers=H, timeout=30).json()
    if t["status"] == "completed":
        sol = t["solution"]
        break
    if t["status"] in ("failed", "cancelled"):
        raise RuntimeError(t.get("errorCode"))
    time.sleep(2)

jar = sol["cookies"]          # _abck, bm_sz, ak_bmsc
extra = sol.get("headers") or {}   # documented as possibly null
session = requests.Session()
session.cookies.update(jar)
session.headers["User-Agent"] = sol["useragent"]
session.headers.update(extra)
session.proxies = {"http": "http://203.0.113.10:8080",
                   "https": "http://203.0.113.10:8080"}

def marker(cookie_value):
    segs = cookie_value.split("~")
    return [s for s in segs if s in ("0", "-1")]

r = session.get("https://example.com/product/42", timeout=30)
session.cookies.update(r.cookies)          # keep the rewrite, not just the seed
if marker(session.cookies.get("_abck", ""))[-1:] == ["-1"]:
    raise RuntimeError("challenge in disguise: 200 with a pending sensor marker")
</code></pre>
<p>Two details in that snippet are the ones people skip. <code>session.cookies.update(r.cookies)</code> after every response — that is the rewrite. And the marker check reading the last marker segment rather than testing for the substring <code>~0~</code>, because a value that contains both markers is normal and is not a pass.</p>
<h2>The five-item check</h2>
<ol>
<li>Am I replaying the seed cookie, or the updated one from the last response?</li>
<li>Do I carry <code>bm_sz</code> and <code>ak_bmsc</code> alongside <code>_abck</code>?</li>
<li>Does the last marker segment read <code>0</code>, not just exist?</li>
<li>If <code>solution.headers</code> was not null, did I actually send them?</li>
<li>Does the page need an <code>ApiURL</code> POST before the session is considered real?</li>
</ol>
<h2>The rule</h2>
<p>On Akamai the cookie is not a key you are handed, it is a ledger the server keeps updating. Read the last marker, store every rewrite, send back the headers that came with it, and let the body — not the status code — tell you whether you passed.</p>
<p>I maintain SolveHub, a CAPTCHA and anti-bot solving API for authorised testing. The Akamai endpoint, its request fields and the <code>ApiURL</code> behaviour are documented at <a href="https://www.tiam.codes/docs/akamai">https://www.tiam.codes/docs/akamai</a>.</p>
]]></content:encoded></item></channel></rss>