Tích Hợp

Tích hợp Vault để quản lý khóa API CaptchaAI

Khóa API được mã hóa cứng trong mã nguồn là một trách nhiệm bảo mật. HashiCorp Vault tập trung quản lý bí mật - của bạnCaptchaAIKhóa API được lưu trữ dưới dạng mã hóa, được truy xuất trong thời gian chạy và mọi truy cập đều được ghi lại. Hướng dẫn này trình bày cách tích hợp Vault vào quy trình giải CAPTCHA của bạn.

Tại sao Vault dành cho Khóa API CAPTCHA

không có kho tiền Với Vault
Khóa API trong tệp hoặc mã .env Khóa được lưu trữ được mã hóa trong Vault
Khóa được chia sẻ qua Slack hoặc email Truy cập thông qua API được xác thực
Không có dấu vết kiểm tra quyền truy cập Mỗi lần đọc được ghi lại với danh tính
Xoay phím thủ công Hỗ trợ xoay tự động
Cùng một khóa trên các môi trường Khóa theo môi trường có chính sách

Điều kiện tiên quyết

  • Máy chủ HashiCorp Vault (tự lưu trữ hoặc HCP Vault)
  • Truy cập Vault CLI hoặc API
  • Khóa API CaptchaAI
  • Python 3.8+ hoặc Node.js 18+

Lưu trữ khóa API trong 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

Tạo chính sách Vault

Hạn chế nhân viên CAPTCHA truy cập chỉ đọc:

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

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

Áp dụng chính sách:

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

Tích hợp 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]}...")

Tích hợp 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)}...`);
})();

Phương thức xác thực

Vault hỗ trợ nhiều phương thức xác thực cho công nhân:

phương pháp Tốt nhất cho thiết lập
Mã thông báo Phát triển, CI/CD VAULT_TOKEN env var
AppRole Dịch vụ sản xuất ID vai trò + ID bí mật
Kubernetes Khối lượng công việc của K8 Tài khoản dịch vụ JWT
AWS IAM Công nhân EC2/Lambda Vai trò sơ thẩm

Ví dụ về AppRole (Được đề xuất cho sản xuất)

# 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"]

Quy trình làm việc xoay phím

  1. Tạo khóa API CaptchaAI mới trong bảng điều khiển CaptchaAI
  2. Cập nhật Vault: vault kv put secret/captchaai api_key="NEW_KEY"
  3. Công nhân tự động nhận khóa mới trong chu kỳ làm mới tiếp theo
  4. Thu hồi khóa cũ trong bảng điều khiển CaptchaAI sau khi tất cả công nhân đã làm mới

Không cần thay đổi mã hoặc triển khai.

Khắc phục sự cố

Vấn đề Nguyên nhân Cách xử lý
403 Forbidden từ Vault Chính sách không cho phép đọc Kiểm tra đường dẫn captcha-worker-policy.hcl
VAULT_TOKEN đã hết hạn Đã vượt quá mã thông báo TTL Sử dụng AppRole cho mã thông báo có thể tự động tái tạo
Chìa khóa không được làm mới Khoảng thời gian làm mới quá dài Giảm _key_refresh_interval
Vault không có sẵn Sự cố mạng hoặc máy chủ Khóa bộ đệm cục bộ có dự phòng

Câu hỏi thường gặp

Điều gì xảy ra nếu Vault ngừng hoạt động?

Lưu khóa API vào bộ nhớ khi truy xuất lần đầu. Nếu Vault không khả dụng trong quá trình làm mới, hãy tiếp tục sử dụng khóa đã lưu trong bộ nhớ đệm và ghi lại lỗi.

Tôi có nên lưu trữ một khóa cho mỗi môi trường không?

Vâng. Sử dụng các đường dẫn Vault riêng biệt: secret/captchaai/dev, secret/captchaai/staging, secret/captchaai/prod.

Tôi có thể sử dụng AWS Secrets Manager thay vì Vault không?

Vâng. Mẫu này giống hệt nhau — truy xuất bí mật trong thời gian chạy từ AWS Secrets Manager bằng boto3. Nguyên tắc cốt lõi (không có khóa mã hóa cứng, xoay vòng mà không cần triển khai) vẫn giữ nguyên.

bài viết liên quan

Các bước tiếp theo

Bảo mật thông tin xác thực CaptchaAI của bạn với Vault —lấy khóa API của bạn.

Hướng dẫn liên quan:

Os comentários estão desativados para este artigo.