Kasada 是互联网上最先进的机器人防护系统之一,被 Twitch、Kick、Nike 和 Arc'teryx 等网站使用。与 Cloudflare Turnstile 不同,很少有解决方案支持 Kasada — 网上几乎没有关于如何绕过它的文档。在本指南中,您将了解 Kasada 的工作原理、为什么难以绕过,以及如何使用 NSLSolver API 以编程方式解决它。
什么是 Kasada?
Kasada(前身为 Kasada IPS)是一个结合浏览器指纹识别和工作量证明(PoW)挑战的机器人防护平台。它旨在在边缘检测和阻止自动化流量,甚至在请求到达源服务器之前。
Kasada 保护着一些全球流量最大的平台:
- Twitch — 直播平台(登录、GQL API)
- Kick — 直播和实时内容平台
- Nike — 限量球鞋发售和产品页面
- Arc'teryx — 户外服装(结账和账户)
Kasada 防护的工作原理
当浏览器访问受 Kasada 保护的页面时,会发生以下流程:
- 页面从目标域名的唯一路径加载一个名为 p.js 的 JavaScript 文件。
- p.js 收集大量浏览器指纹 — canvas、WebGL、音频上下文、navigator 属性、屏幕尺寸、已安装字体等。
- 脚本生成工作量证明解决方案(一个计算密集型哈希挑战),以证明客户端是真实浏览器。
- 指纹和 PoW 结果被打包成 x-kpsdk-ct(客户端令牌)、x-kpsdk-cd(挑战数据)、x-kpsdk-v(版本)和 x-kpsdk-h(硬件哈希)请求头。
对受保护 API 的每个后续请求都必须包含这些有效且未过期的请求头。否则,服务器会返回 429 或重定向到挑战页面。
为什么 Kasada 难以绕过
Kasada 比大多数验证码系统难绕过得多:
- 重度浏览器指纹识别 — Kasada 收集 50 多个浏览器信号,并与已知浏览器配置文件进行比较。无头浏览器和伪造的用户代理会被立即检测到。
- 工作量证明挑战 — PoW 组件需要真实的计算工作,防止简单的重放攻击,并增加暴力破解的延迟。
- 频繁更新 — Kasada 定期更改其检测方法、指纹收集和 p.js 混淆。今天有效的解决方案明天可能失效。
- 很少有解决方案支持它 — 大多数验证码解决服务(2Captcha、Anti-Captcha、CapSolver)根本不提供 Kasada 解决,使其成为最难绕过的防护之一。
解决方案:NSLSolver Kasada API
NSLSolver 在服务端处理整个 Kasada 挑战流程。您发送目标 URL 和配置,我们返回您需要的 x-kpsdk 请求头:
- 无需浏览器 — 我们在基础设施上解决挑战,只返回请求头。
- 始终保持最新 — 我们监控 Kasada 的变化并自动更新解决器。
- 简单的 REST API — 一个 POST 请求,几秒钟内获取请求头。
第一步:安装 SDK
安装官方 NSLSolver Python SDK——它会替你处理 HTTP、重试和类型化的结果。如果你更想直接调用 REST API,下面也给出了仅依赖 requests 的写法。
pip install nslsolver
# or, for the plain-requests path below: pip install requests第二步:了解参数
Kasada 解决需要比简单验证码更多的参数。您需要检查目标网站的网络流量来找到这些值:
| 参数 | 必填 | 说明 |
|---|---|---|
| url | 是 | 受 Kasada 保护页面的完整 URL |
| user_agent | 是 | 浏览器的 User-Agent 字符串 — 后续请求中必须完全匹配 |
| ua_version | 是 | User-Agent 中的 Chrome 主版本号(例如 145) |
| kasada_config.p_js_path | 是 | Kasada p.js 脚本的路径 — 在浏览器的网络标签中查找 |
| kasada_config.fp_host | 是 | 提供 Kasada 指纹页面的主机名(通常是登录域名) |
| kasada_config.tl_host | 是 | Kasada TL 令牌端点的主机名(通常是 API 域名) |
第三步:解决 Kasada 挑战
用 SDK 最简单:实例化 NSLSolver,调用 solve_kasada(...),并通过 KasadaConfig 传入 p.js 路径与主机名。以下是一个 Twitch 示例:
from nslsolver import NSLSolver, KasadaConfig
solver = NSLSolver("nsl_YOUR_API_KEY")
result = solver.solve_kasada(
url="https://passport.twitch.tv",
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36",
ua_version=145,
kasada_config=KasadaConfig(
p_js_path="/149e9513-01fa-4fb0-aad4-566afd725d1b/2d206a39-8ed7-437e-a3be-862e0f06eea3/p.js",
fp_host="passport.twitch.tv",
tl_host="gql.twitch.tv",
),
)
# result.headers holds the x-kpsdk-* headers; result.ct / result.cd are shortcuts
print(result.headers)更喜欢不加依赖?同样的解题也可以用一个普通的 requests POST 完成——payload 与 SDK 内部发送的完全一致:
import requests
API_KEY = "nsl_YOUR_API_KEY"
response = requests.post(
"https://api.nslsolver.com/solve",
headers={"X-API-Key": API_KEY},
json={
"type": "kasada",
"url": "https://passport.twitch.tv",
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36",
"ua_version": 145,
"kasada_config": {
"p_js_path": "/149e9513-01fa-4fb0-aad4-566afd725d1b/2d206a39-8ed7-437e-a3be-862e0f06eea3/p.js",
"fp_host": "passport.twitch.tv",
"tl_host": "gql.twitch.tv"
}
}
)
data = response.json()
print(data["headers"])API 返回您需要的已解决 x-kpsdk 请求头:
{
"success": true,
"headers": {
"x-kpsdk-ct": "eyJ0eXAi...a_long_token",
"x-kpsdk-cd": "AQAAAJY...proof_of_work_solution",
"x-kpsdk-v": "j-0.0.0",
"x-kpsdk-h": "SW50ZWw...browser_hash"
},
"cost": 0.0015
}第四步:在请求中使用请求头
将返回的请求头附加到对受保护 API 的请求中。确保 User-Agent 与您传递给解决器的完全匹配:
import requests
# After solving Kasada with NSLSolver:
kasada_headers = data["headers"]
# Make your request with the solved headers
response = requests.post(
"https://gql.twitch.tv/gql",
headers={
"x-kpsdk-ct": kasada_headers["x-kpsdk-ct"],
"x-kpsdk-cd": kasada_headers["x-kpsdk-cd"],
"x-kpsdk-v": kasada_headers["x-kpsdk-v"],
"x-kpsdk-h": kasada_headers["x-kpsdk-h"],
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36",
"Content-Type": "application/json"
},
json={"query": "..."}
)
print(response.status_code)完整示例(含错误处理)
下面是用官方 SDK 编写的生产级示例。SDK 会自动对 429/503 做指数退避重试,并把失败映射为类型化的异常,因此你的代码更简洁:
from nslsolver import NSLSolver, KasadaConfig, NSLSolverError
API_KEY = "nsl_YOUR_API_KEY"
TARGET_URL = "https://passport.twitch.tv"
USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36"
solver = NSLSolver(API_KEY)
def solve_kasada():
"""Solve a Kasada challenge via the NSLSolver SDK (auto-retries 429/503)."""
try:
result = solver.solve_kasada(
url=TARGET_URL,
user_agent=USER_AGENT,
ua_version=145,
kasada_config=KasadaConfig(
p_js_path="/149e9513-01fa-4fb0-aad4-566afd725d1b/2d206a39-8ed7-437e-a3be-862e0f06eea3/p.js",
fp_host="passport.twitch.tv",
tl_host="gql.twitch.tv",
),
)
return result.headers
except NSLSolverError as e:
print(f"Kasada solve failed: {e}")
return None
# Solve and use the headers
headers = solve_kasada()
if headers:
resp = requests.post(
"https://gql.twitch.tv/gql",
headers={**headers, "User-Agent": USER_AGENT},
json={"query": "..."},
)
print(f"Status: {resp.status_code}")如果你不想引入 SDK,这里是仅依赖 requests 的等价实现,自带重试与错误处理:
import requests
import time
API_KEY = "nsl_YOUR_API_KEY"
TARGET_URL = "https://passport.twitch.tv"
USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36"
def solve_kasada(retries=3):
"""Solve a Kasada challenge via the NSLSolver REST API."""
for attempt in range(retries):
try:
resp = requests.post(
"https://api.nslsolver.com/solve",
headers={"X-API-Key": API_KEY},
json={
"type": "kasada",
"url": TARGET_URL,
"user_agent": USER_AGENT,
"ua_version": 145,
"kasada_config": {
"p_js_path": "/149e9513-01fa-4fb0-aad4-566afd725d1b/2d206a39-8ed7-437e-a3be-862e0f06eea3/p.js",
"fp_host": "passport.twitch.tv",
"tl_host": "gql.twitch.tv"
},
},
timeout=60
)
resp.raise_for_status()
data = resp.json()
if data.get("success"):
return data["headers"]
print(f"Attempt {attempt + 1} failed: {data}")
except requests.RequestException as e:
print(f"Request error: {e}")
if attempt < retries - 1:
time.sleep(3)
return None
# Solve and use the headers
headers = solve_kasada()
if headers:
print("Got Kasada headers, making request...")
resp = requests.post(
"https://gql.twitch.tv/gql",
headers={
**headers,
"User-Agent": USER_AGENT,
"Content-Type": "application/json"
},
json={"query": "..."}
)
print(f"Status: {resp.status_code}")
else:
print("Failed to solve Kasada after retries.")定价与性能
Kasada 解决按次计费,反映了 PoW 挑战的计算成本:
- 每 1,000 次解决 $1.50 — 仅对成功的解决收费
- 平均解决时间 3-10 秒 — PoW 挑战比简单验证码耗时更长
- 90%+ 成功率 — 我们持续监控并适应 Kasada 的频繁更新
延伸阅读: Kasada 解决方案页、查看完整 价格,或在 对比页比较各家求解器。
重要提示:您传递给 NSLSolver 的 User-Agent 必须与您在后续请求中使用的 User-Agent 完全匹配。Kasada 会将此请求头与指纹进行验证 — 不匹配将导致立即被封。