Une clé API CaptchaAI est un identifiant au porteur : quiconque la détient peut consommer votre solde, sans mot de passe ni second facteur. La protéger tient à quatre gestes :
- La sortir du code source et la charger depuis l'environnement.
- Restreindre les adresses IP autorisées lorsque le tableau de bord le permet.
- La faire tourner régulièrement.
- L'expurger systématiquement des journaux.
Ce guide déroule chacun de ces gestes avec du code Python directement réutilisable.
Par où fuit une clé API ?
La plupart des fuites ne viennent pas d'une attaque sophistiquée, mais d'un geste banal : un dépôt privé cloné puis forké, une capture d'écran de terminal, une trace d'erreur remontée dans un outil de supervision — et la clé se retrouve hors de votre contrôle.
Exposed API key:
├── Leaked in Git repository
├── Hardcoded in client-side code
├── Shared in documentation
└── Visible in logs
Impact:
├── Balance drained by unauthorized users
├── Usage spikes from abuse
└── Key disabled by service provider
Chaque vecteur appelle un correctif précis :
- Dépôt Git — ne versionnez jamais la clé ; passez par un fichier
.envignoré. - Code côté client — gardez la clé côté serveur, jamais dans un bundle livré au navigateur.
- Documentation partagée — remplacez la vraie valeur par le placeholder
YOUR_API_KEY. - Logs serveur — expurgez la clé avant toute écriture.
Les conséquences sont immédiates : le solde se vide, le volume de requêtes explose sous l'effet d'un usage frauduleux, et le fournisseur peut désactiver la clé le temps de l'incident. Côté conformité, un secret qui traîne dans des journaux exportés vers un tiers est une donnée sensible : appliquez le principe RGPD de minimisation.
Sortez la clé API du code source
La règle de base ne souffre aucune exception : une clé n'a rien à faire dans le code versionné. Deux emplacements sûrs :
- une variable d'environnement ;
- un fichier
.envexclu du dépôt.
Ne codez jamais la clé en dur
# BAD — key in source code
API_KEY = "abc123def456" # DO NOT DO THIS
# GOOD — environment variable
import os
API_KEY = os.environ["CAPTCHAAI_API_KEY"]
# GOOD — .env file (not committed to Git)
from dotenv import load_dotenv
load_dotenv()
API_KEY = os.environ["CAPTCHAAI_API_KEY"]
Le fichier .env
Regroupez vos secrets dans un fichier .env local, jamais versionné, que chaque développeur remplit avec sa propre clé :
# .env (add to .gitignore!)
CAPTCHAAI_API_KEY=your_api_key_here
Le .gitignore
Le fichier .env ne vaut que si Git l'ignore vraiment. Ajoutez la règle avant le premier commit, pas après :
# Always ignore .env files
.env
.env.local
.env.production
Charger la configuration depuis l'environnement
Centralisez la lecture de la clé dans une classe de configuration. Elle échoue tôt si la variable est absente et vérifie que la clé fonctionne en interrogeant le solde via res.php, plutôt que d'échouer au premier CAPTCHA soumis.
import os
class CaptchaConfig:
"""Load CaptchaAI config from environment."""
def __init__(self):
self.api_key = os.environ.get("CAPTCHAAI_API_KEY")
if not self.api_key:
raise EnvironmentError(
"CAPTCHAAI_API_KEY not set. "
"Set it in your environment or .env file."
)
self.base_url = os.environ.get(
"CAPTCHAAI_URL", "https://ocr.captchaai.com"
)
def validate(self):
"""Verify the API key works."""
import requests
resp = requests.get(f"{self.base_url}/res.php", params={
"key": self.api_key,
"action": "getbalance",
"json": 1,
}, timeout=10)
data = resp.json()
if data.get("status") != 1:
raise RuntimeError(f"Invalid API key: {data.get('request')}")
return float(data["request"])
# Usage
config = CaptchaConfig()
balance = config.validate()
print(f"Key valid, balance: ${balance:.2f}")
Faire tourner les clés API régulièrement
Une clé qui ne change jamais est une clé qui finira par fuir sans que vous le sachiez. Prévoyez une rotation périodique et gardez une clé secondaire prête, afin de basculer sans interruption de service si la clé primaire est compromise. Déclenchez une rotation dans trois cas :
- à intervalle régulier, par exemple tous les 90 jours ;
- au départ d'une personne ayant eu accès à la clé ;
- dès qu'une fuite est suspectée, même sans preuve formelle.
import os
import datetime
class KeyManager:
"""Manage API key rotation."""
def __init__(self):
self.primary_key = os.environ.get("CAPTCHAAI_API_KEY")
self.secondary_key = os.environ.get("CAPTCHAAI_API_KEY_BACKUP")
self.active_key = self.primary_key
def get_key(self):
return self.active_key
def rotate(self):
"""Switch to secondary key."""
if self.secondary_key:
self.active_key = self.secondary_key
print("Rotated to secondary key")
else:
print("No secondary key configured")
def test_key(self, key):
"""Verify a key is valid."""
import requests
resp = requests.get("https://ocr.captchaai.com/res.php", params={
"key": key, "action": "getbalance", "json": 1,
}, timeout=10)
return resp.json().get("status") == 1
# Usage
keys = KeyManager()
# If primary fails, rotate to secondary
if not keys.test_key(keys.get_key()):
keys.rotate()
Valider les requêtes avant de les envoyer
Un paramètre mal formé, c'est une requête gaspillée. Validez la méthode et l'URL cible avant l'appel, et journalisez ce que vous soumettez sans jamais y inclure la clé.
import requests
import logging
logger = logging.getLogger(__name__)
class SecureSolver:
"""Solver with security best practices."""
def __init__(self, api_key):
self.api_key = api_key
self.base = "https://ocr.captchaai.com"
def solve(self, method, **params):
# Validate inputs
self._validate_params(method, params)
data = {"key": self.api_key, "method": method, "json": 1}
data.update(params)
# Log without exposing key
logger.info(
"Submitting %s solve for %s",
method, params.get("pageurl", "unknown"),
)
resp = requests.post(
f"{self.base}/in.php", data=data, timeout=30,
)
return resp.json()
def _validate_params(self, method, params):
"""Prevent common security mistakes."""
# Ensure pageurl is a valid URL
pageurl = params.get("pageurl", "")
if pageurl and not pageurl.startswith(("http://", "https://")):
raise ValueError(f"Invalid pageurl: {pageurl}")
# Ensure method is valid
valid_methods = {
"userrecaptcha", "turnstile", "geetest",
"base64", "post", "bls", "cloudflare_challenge",
}
if method not in valid_methods:
raise ValueError(f"Unknown method: {method}")
La liste valid_methods reflète les types réellement pris en charge :
- reCAPTCHA —
userrecaptcha - Cloudflare Turnstile —
turnstile - Cloudflare Challenge —
cloudflare_challenge - GeeTest v3 —
geetest - image/OCR —
post,base64 - BLS CAPTCHA —
bls
Adaptez-la à votre usage plutôt que d'accepter n'importe quelle chaîne.
Journaliser sans exposer la clé API
Les logs sont la fuite la plus discrète : ils partent souvent vers un service d'agrégation externe. Un formateur qui masque tout ce qui ressemble à une clé empêche qu'un secret n'atterrisse dans une trace.
import logging
import re
logger = logging.getLogger(__name__)
class SafeFormatter(logging.Formatter):
"""Redact API keys from log messages."""
KEY_PATTERN = re.compile(r'[a-f0-9]{32}', re.IGNORECASE)
def format(self, record):
msg = super().format(record)
return self.KEY_PATTERN.sub("[REDACTED]", msg)
# Configure safe logging
handler = logging.StreamHandler()
handler.setFormatter(SafeFormatter("%(levelname)s: %(message)s"))
logger.addHandler(handler)
logger.setLevel(logging.INFO)
# Key is automatically redacted in logs
logger.info(f"Using key: abc123def456ghi789jkl012mno345pq")
# Output: INFO: Using key: [REDACTED]
Gérer les secrets dans Docker
Sur des workers déployés chez OVHcloud, Scaleway ou dans la région AWS eu-west-3 (Paris), la clé arrive par variable d'environnement ou par le mécanisme de secrets Docker, jamais gravée dans l'image — sinon elle devient lisible par quiconque peut la télécharger.
# Dockerfile — DO NOT embed keys here
FROM python:3.11-slim
WORKDIR /app
COPY . .
RUN pip install requests
CMD ["python", "solver.py"]
# docker-compose.yml
services:
solver:
build: .
environment:
- CAPTCHAAI_API_KEY=${CAPTCHAAI_API_KEY}
# Or use Docker secrets:
secrets:
- captchaai_key
secrets:
captchaai_key:
file: ./secrets/captchaai_key.txt
Deux approches valables selon votre orchestrateur :
- Variable d'environnement — simple, injectée depuis l'hôte au démarrage du conteneur.
- Secret Docker — monté en fichier, jamais présent dans les variables d'environnement du processus.
Sécuriser la clé API dans la CI/CD
Dans un pipeline d'intégration continue, la clé vit dans le coffre de secrets de la plateforme, jamais dans le fichier de workflow. GitHub Actions injecte la valeur au moment de l'exécution via secrets.CAPTCHAAI_API_KEY, sans jamais l'afficher dans les logs de build.
# .github/workflows/test.yml
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run tests
env:
CAPTCHAAI_API_KEY: ${{ secrets.CAPTCHAAI_API_KEY }}
run: python test_solver.py
Trois réflexes pour une CI sûre :
- ne faites jamais un
echodu secret pour déboguer ; - limitez la portée du secret au seul job qui en a besoin ;
- désactivez l'affichage des variables sensibles dans les logs de build.
Dépannage
| Problème | Cause probable | Correctif |
|---|---|---|
ERROR_WRONG_USER_KEY |
Clé incorrecte ou expirée | Recopiez la clé depuis le tableau de bord CaptchaAI |
| Ponction inattendue du solde | Clé divulguée ou partagée | Faites tourner la clé immédiatement et auditez les accès |
| La clé fonctionne en local mais pas en CI | Variable d'environnement absente | Ajoutez-la aux secrets de la CI/CD |
| Clé présente dans l'historique Git | Fichier .env versionné par erreur |
Faites tourner la clé, ajoutez .env au .gitignore, réécrivez l'historique avec git filter-branch |
Check-list de sécurité
- ☐ Clé API dans une variable d'environnement
- ☐
.envajouté au.gitignore - ☐ Aucune clé dans le code source
- ☐ Clés expurgées dans les journaux
- ☐ La CI/CD utilise un gestionnaire de secrets
- ☐ Calendrier de rotation des clés en place
- ☐ Surveillance du solde active
FAQ
La liste blanche IP est-elle disponible dans CaptchaAI ?
Ouvrez votre tableau de bord CaptchaAI et cherchez les paramètres de restriction par adresse IP. Si l'option est proposée, n'autorisez que les IP de vos serveurs : une clé volée devient alors inutilisable en dehors de votre infrastructure.
Faut-il des clés différentes pour le développement et la production ?
Oui. Des clés distinctes pour le développement, la préproduction et la production limitent le rayon d'impact : une clé de dev qui fuit n'expose pas votre solde de production.
Comment purger une clé API de l'historique Git ?
Faites d'abord tourner la clé : l'historique reste accessible sur tous les clones existants. Réécrivez ensuite l'historique avec git filter-branch ou git filter-repo, puis forcez la mise à jour du dépôt distant.
Comment repérer une clé compromise avant qu'elle ne vide le solde ?
Surveillez le solde en continu via res.php avec action=getbalance. Deux signaux trahissent un usage frauduleux :
- un pic de requêtes en dehors de vos fenêtres d'activité ;
- une chute brutale du solde sans campagne correspondante.
Les variables d'environnement suffisent-elles à sécuriser la clé ?
Elles sont la base, pas la fin. Combinez-les avec l'expurgation dans les logs, une rotation régulière et un gestionnaire de secrets en CI/CD — chaque couche ferme une voie de fuite différente.
Guides connexes
Protégez votre investissement : sécurisez dès aujourd'hui votre clé API CaptchaAI.