集成指南

CaptchaAI API 密钥管理的 Vault 集成

源代码中的硬编码 API 密钥是一种安全责任。 HashiCorp Vault 集中秘密管理——您的CaptchaAIAPI 密钥以加密方式存储,在运行时检索,并且每次访问都会被记录。本指南介绍如何将 Vault 集成到验证码解决管道中。

为何使用 CAPTCHA API 密钥保管库

没有保险库 带保险库
.env 文件或代码中的 API 密钥 密钥加密存储在 Vault 中
通过 Slack 或电子邮件共享密钥 通过经过身份验证的 API 访问
无访问审计跟踪 每次读取都会记录身份
手动钥匙轮换 自动旋转支持
跨环境使用相同的密钥 具有策略的每个环境密钥

先决条件

  • HashiCorp Vault 服务器(自托管或 HCP Vault)
  • Vault CLI 或 API 访问
  • CaptchaAI API 密钥
  • Python 3.8+ 或 Node.js 18+

将 API 密钥存储在 Vault 中

# Enable the KV secrets engine (if not already enabled)
vault secrets enable -path=secret kv-v2

# Store the CaptchaAI API key
vault kv put secret/captchaai api_key="YOUR_API_KEY"

# Verify
vault kv get secret/captchaai

创建保管库策略

限制 CAPTCHA 工作人员的只读访问权限:

# captcha-worker-policy.hcl
path "secret/data/captchaai" {
  capabilities = ["read"]
}

path "secret/metadata/captchaai" {
  capabilities = ["read"]
}

应用政策:

vault policy write captcha-worker captcha-worker-policy.hcl

Python集成

# vault_solver.py
import os
import time
import hvac
import requests

# Connect to Vault
vault_client = hvac.Client(
    url=os.environ.get("VAULT_ADDR", "http://127.0.0.1:8200"),
    token=os.environ.get("VAULT_TOKEN"),
)

def get_api_key():
    """Retrieve CaptchaAI API key from Vault."""
    secret = vault_client.secrets.kv.v2.read_secret_version(
        path="captchaai",
        mount_point="secret",
    )
    return secret["data"]["data"]["api_key"]

class CaptchaSolver:
    """CAPTCHA solver with Vault-managed credentials."""

    def __init__(self):
        self.api_key = get_api_key()
        self.session = requests.Session()
        self._key_fetched_at = time.time()
        self._key_refresh_interval = 3600  # Re-fetch key hourly

    def _refresh_key_if_needed(self):
        """Periodically refresh the key from Vault."""
        if time.time() - self._key_fetched_at > self._key_refresh_interval:
            self.api_key = get_api_key()
            self._key_fetched_at = time.time()

    def solve(self, sitekey, pageurl):
        """Solve reCAPTCHA v2 using Vault-managed key."""
        self._refresh_key_if_needed()

        # Submit
        resp = self.session.get("https://ocr.captchaai.com/in.php", params={
            "key": self.api_key,
            "method": "userrecaptcha",
            "googlekey": sitekey,
            "pageurl": pageurl,
            "json": "1",
        })
        result = resp.json()

        if result.get("status") != 1:
            raise Exception(f"Submit failed: {result.get('request')}")

        task_id = result["request"]
        time.sleep(15)

        for _ in range(25):
            poll = self.session.get("https://ocr.captchaai.com/res.php", params={
                "key": self.api_key,
                "action": "get",
                "id": task_id,
                "json": "1",
            })
            poll_result = poll.json()

            if poll_result.get("status") == 1:
                return poll_result["request"]
            if poll_result.get("request") != "CAPCHA_NOT_READY":
                raise Exception(f"Error: {poll_result.get('request')}")

            time.sleep(5)

        raise Exception("Timeout")

# Usage
solver = CaptchaSolver()
token = solver.solve(
    "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
    "https://www.google.com/recaptcha/api2/demo"
)
print(f"Token: {token[:30]}...")

JavaScript 集成

// vault_solver.js
const axios = require('axios');

const VAULT_ADDR = process.env.VAULT_ADDR || 'http://127.0.0.1:8200';
const VAULT_TOKEN = process.env.VAULT_TOKEN;

async function getApiKey() {
  const resp = await axios.get(
    `${VAULT_ADDR}/v1/secret/data/captchaai`,
    { headers: { 'X-Vault-Token': VAULT_TOKEN } }
  );
  return resp.data.data.data.api_key;
}

class CaptchaSolver {
  constructor() {
    this.apiKey = null;
    this.keyFetchedAt = 0;
    this.refreshInterval = 3600000; // 1 hour
  }

  async init() {
    this.apiKey = await getApiKey();
    this.keyFetchedAt = Date.now();
  }

  async refreshKeyIfNeeded() {
    if (Date.now() - this.keyFetchedAt > this.refreshInterval) {
      this.apiKey = await getApiKey();
      this.keyFetchedAt = Date.now();
    }
  }

  async solve(sitekey, pageurl) {
    await this.refreshKeyIfNeeded();

    const submit = await axios.get('https://ocr.captchaai.com/in.php', {
      params: {
        key: this.apiKey, method: 'userrecaptcha',
        googlekey: sitekey, pageurl, json: '1',
      },
    });

    if (submit.data.status !== 1) throw new Error(submit.data.request);
    const taskId = submit.data.request;

    await new Promise(r => setTimeout(r, 15000));

    for (let i = 0; i < 25; i++) {
      const poll = await axios.get('https://ocr.captchaai.com/res.php', {
        params: { key: this.apiKey, action: 'get', id: taskId, json: '1' },
      });

      if (poll.data.status === 1) return poll.data.request;
      if (poll.data.request !== 'CAPCHA_NOT_READY') throw new Error(poll.data.request);
      await new Promise(r => setTimeout(r, 5000));
    }
    throw new Error('Timeout');
  }
}

(async () => {
  const solver = new CaptchaSolver();
  await solver.init();

  const token = await solver.solve(
    '6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-',
    'https://www.google.com/recaptcha/api2/demo'
  );
  console.log(`Token: ${token.slice(0, 30)}...`);
})();

认证方式

Vault 支持工作人员的多种身份验证方法:

方法 最适合 设置
代币 开发,CI/CD VAULT_TOKEN 环境变量
应用角色 生产服务 角色ID+秘密ID
库伯内斯 K8s 工作负载 服务帐户 JWT
AWS IAM EC2/Lambda 工人 实例角色

AppRole 示例(推荐用于生产)

# AppRole authentication — no static token needed
vault_client = hvac.Client(url=os.environ["VAULT_ADDR"])
vault_client.auth.approle.login(
    role_id=os.environ["VAULT_ROLE_ID"],
    secret_id=os.environ["VAULT_SECRET_ID"],
)

# Now read the secret
secret = vault_client.secrets.kv.v2.read_secret_version(path="captchaai")
api_key = secret["data"]["data"]["api_key"]

密钥轮换工作流程

  1. 在 CaptchaAI 仪表板中生成新的 CaptchaAI API 密钥
  2. 更新金库:vault kv put secret/captchaai api_key="NEW_KEY"
  3. 工作人员在下一个刷新周期自动获取新钥匙
  4. 所有工作人员刷新后,撤销 CaptchaAI 仪表板中的旧密钥

无需更改代码或部署。

故障排除

问题 原因 处理方式
来自 Vault 的 403 Forbidden 策略不允许读取 检查 captcha-worker-policy.hcl 路径
VAULT_TOKEN 已过期 令牌 TTL 超出 使用 AppRole 来自动更新令牌
按键不刷新 刷新间隔太长 减少_key_refresh_interval
保险库不可用 网络或服务器问题 通过回退在本地缓存密钥

常问问题

如果 Vault 宕机了会发生什么?

首次检索时将 API 密钥缓存在内存中。如果 Vault 在刷新期间不可用,请继续使用缓存的密钥并记录失败。

我应该为每个环境存储一个密钥吗?

是的。使用单独的Vault路径:secret/captchaai/devsecret/captchaai/stagingsecret/captchaai/prod

我可以使用 AWS Secrets Manager 代替 Vault 吗?

是的。模式是相同的 - 使用 boto3 在运行时从 AWS Secrets Manager 检索密钥。核心原则(无硬编码密钥,无需部署即可轮换)保持不变。

相关文章

下一步

使用 Vault 保护您的 CaptchaAI 凭证 -获取您的 API 密钥

相关指南:

该文章已禁用评论。