Las claves API codificadas en el código fuente son una responsabilidad de seguridad. HashiCorp Vault centraliza la gestión de secretos: suCaptchaAILa clave API se almacena cifrada, se recupera en tiempo de ejecución y se registra cada acceso. Esta guía muestra cómo integrar Vault en su proceso de resolución de CAPTCHA.
Por qué Vault para claves API CAPTCHA
| Sin bóveda | Con bóveda |
|---|---|
Clave API en el archivo o código .env |
Clave almacenada cifrada en Vault |
| Clave compartida a través de Slack o correo electrónico | Acceso a través de API autenticada |
| Sin pista de auditoría de acceso | Cada lectura registrada con identidad |
| Rotación manual de llaves | Soporte de rotación automatizado |
| La misma clave en todos los entornos | Claves por entorno con políticas |
Requisitos previos
- Servidor HashiCorp Vault (autohospedado o HCP Vault)
- Acceso a Vault CLI o API
- Clave API CaptchaAI
- Python 3.8+ o Node.js 18+
Almacene la clave API en 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
Crear una política de bóveda
Restrinja a los trabajadores de CAPTCHA al acceso de solo lectura:
# captcha-worker-policy.hcl
path "secret/data/captchaai" {
capabilities = ["read"]
}
path "secret/metadata/captchaai" {
capabilities = ["read"]
}
Aplicar la política:
vault policy write captcha-worker captcha-worker-policy.hcl
Integración de 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]}...")
Integración de 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)}...`);
})();
Métodos de autenticación
Vault admite múltiples métodos de autenticación para trabajadores:
| Método | Mejor para | Configuración |
|---|---|---|
| ficha | Desarrollo, CI/CD | VAULT_TOKEN var env |
| Función de aplicación | Servicios de producción | ID de rol + ID secreto |
| Kubernetes | Cargas de trabajo de K8 | Cuenta de servicio JWT |
| AWSIAM | Trabajadores EC2/Lambda | Rol de instancia |
Ejemplo de AppRole (recomendado para producción)
# 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"]
Flujo de trabajo de rotación de claves
- Genere una nueva clave API CaptchaAI en el panel CaptchaAI
- Actualizar bóveda:
vault kv put secret/captchaai api_key="NEW_KEY" - Los trabajadores recogen automáticamente la nueva clave en su próximo ciclo de actualización
- Revocar la clave anterior en el panel CaptchaAI después de que todos los trabajadores se hayan actualizado
No se requieren cambios de código ni implementaciones.
Solución de problemas
| Problema | causa | Solución |
|---|---|---|
403 Forbidden de la bóveda |
La política no permite la lectura. | Verifique la ruta captcha-worker-policy.hcl |
VAULT_TOKEN caducado |
Se superó el TTL del token | Utilice AppRole para tokens renovables automáticamente |
| Clave no refrescante | Intervalo de actualización demasiado largo | Reducir _key_refresh_interval |
| Bóveda no disponible | Problema de red o servidor | Clave de caché local con respaldo |
Preguntas frecuentes
¿Qué sucede si Vault no funciona?
Almacene en caché la clave API en la memoria cuando se recupere por primera vez. Si Vault no está disponible durante una actualización, continúe usando la clave almacenada en caché y registre el error.
¿Debo almacenar una clave por entorno?
Sí. Utilice rutas de Bóveda independientes: secret/captchaai/dev, secret/captchaai/staging, secret/captchaai/prod.
¿Puedo utilizar AWS Secrets Manager en lugar de Vault?
Sí. El patrón es idéntico: recuperar el secreto en tiempo de ejecución de AWS Secrets Manager usando boto3. El principio básico (sin claves codificadas, rotación sin implementaciones) sigue siendo el mismo.
Artículos relacionados
- Seguridad de clave API de lista blanca de IP Captchaai
- Rotación de clave Captchaai Api
- Integración de Captchaai de funciones de Google Cloud
Próximos pasos
Proteja sus credenciales CaptchaAI con Vault:obtenga su clave API.
Guías relacionadas:
- Rotación de claves API
- Protección de credenciales en Env Vars
- Lista blanca de IP