Hướng Dẫn API

Danh sách trắng IP CaptchaAI và bảo mật khóa API

Một khóa API CaptchaAI lộ trên GitHub công khai có thể khiến số dư của bạn về 0 chỉ trong vài giờ — không cần hacker giỏi, chỉ cần một script quét repo thiếu bảo mật. Rủi ro này càng rõ với các đội automation hoặc QA thuê ngoài tại TP.HCM, Hà Nội, nơi nhiều dev cùng đụng vào một repo. Bài viết này gom lại cách lưu khóa an toàn, giới hạn theo IP, xoay khóa định kỳ và việc cần làm ngay khi khóa API rơi vào tay người lạ.


Checklist bảo mật khóa API trước khi triển khai

Rà nhanh bảng này trước khi đưa code lên production — phần còn lại của bài sẽ đi vào chi tiết từng dòng:

Thực hành Trạng thái
Khóa API nằm trong biến môi trường
.env đã có trong .gitignore
Không còn khóa nào hardcode trong mã nguồn
Log đã redact khóa API
CI/CD dùng secrets manager
Có lịch xoay khóa định kỳ
Đang theo dõi số dư để phát hiện bất thường

Khóa API lộ ra ngoài bằng cách nào

Bốn đường lộ khóa phổ biến nhất trong thực tế:

  • Commit nhầm vào Git (kể cả repo private)
  • Hardcode trong code chạy phía client, ai mở DevTools cũng đọc được
  • Dán vào tài liệu chia sẻ nội bộ rồi quên thu hồi quyền truy cập
  • Xuất hiện nguyên văn trong log debug khi request lỗi

Hậu quả gần như luôn giống nhau: số dư bị người lạ dùng trái phép, lưu lượng request tăng bất thường, và nếu nghiêm trọng, CaptchaAI phải tạm khóa key để chặn lạm dụng.

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

Lưu khóa API an toàn, không hardcode

Nguyên tắc đầu tiên: không bao giờ để khóa API nằm thẳng trong mã nguồn, nhất là khi repo có thể public hoặc được chia sẻ ra ngoài team. Biến môi trường và file .env là mức tối thiểu cần có trước khi đưa code lên production.

Không hardcode khóa trong code

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

Đưa khóa vào file .env

# .env (add to .gitignore!)
CAPTCHAAI_API_KEY=your_api_key_here

Thêm .env vào .gitignore

Tạo file .env thôi chưa đủ — nếu quên thêm vào .gitignore, khóa vẫn bị commit như thường, và một khi đã lên Git thì coi như đã lộ dù repo có bị xóa sau đó.

# Always ignore .env files
.env
.env.local
.env.production

Tách cấu hình khóa theo từng môi trường

Đừng dùng chung một cấu hình cho mọi nơi code chạy:

  • Dev: đọc khóa từ .env cục bộ trên máy từng lập trình viên
  • Staging: đọc từ biến môi trường riêng của staging, tách khỏi dev
  • Production: đọc từ secrets manager của nền tảng deploy, không phải file tĩnh

Đoạn code dưới đây chủ động raise lỗi rõ ràng ngay khi thiếu biến môi trường, thay vì để request âm thầm thất bại ở bước gọi API.

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}")

Xoay vòng khóa API định kỳ

Xoay khóa API định kỳ — ví dụ mỗi quý, hoặc ngay khi có người rời dự án — giới hạn thiệt hại nếu một khóa cũ vẫn còn nằm đâu đó trong lịch sử Git hay laptop cá nhân của ai đó.

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()

Giữ sẵn một khóa phụ (secondary key) để chuyển sang ngay khi khóa chính có dấu hiệu bất thường, tránh gián đoạn job đang chạy trong lúc xoay khóa.


Xác thực request trước khi gửi

Validate input trước khi gửi request tới CaptchaAI giúp tránh gửi nhầm dữ liệu rác — vừa tốn quota vô ích, vừa dễ để lộ thông tin nhạy cảm trong log lỗi khi request bị từ chối.

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}")

Ghi log mà không làm lộ khóa

Log debug là nơi khóa API hay lộ ra ngoài ý muốn nhất, vì dev thường in nguyên request để kiểm tra khi có lỗi.

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]

Cách an toàn là gắn một formatter tự động redact chuỗi giống khóa API trước khi ghi ra log, thay vì tự nhắc nhau "nhớ xóa key" bằng tay.


Quản lý secret khi chạy trong Docker

Không copy khóa API vào image Docker và không hardcode trong Dockerfile.

# 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

Image Docker rất dễ bị đẩy nhầm lên registry công khai. Truyền khóa qua biến môi trường lúc container khởi chạy, hoặc dùng Docker secrets cho production.


Bảo mật CI/CD với GitHub Actions

Trên pipeline CI/CD, lưu khóa API trong secrets manager của nền tảng — như GitHub Actions secrets — thay vì hardcode trong file workflow hoặc script 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

Không bao giờ log hoặc echo secret ra output của CI, kể cả khi debug tạm thời.


Sự cố thường gặp và cách xử lý

Vấn đề Nguyên nhân Cách xử lý
ERROR_WRONG_USER_KEY Khóa sai hoặc đã hết hạn Kiểm tra lại khóa trong bảng điều khiển CaptchaAI
Số dư giảm bất thường Khóa bị lộ hoặc bị chia sẻ ngoài ý muốn Xoay khóa ngay, rà soát lại ai đang có quyền truy cập
Khóa chạy được ở local nhưng lỗi trên CI Chưa set biến môi trường trên CI Thêm khóa vào secrets manager của CI/CD
Khóa API còn trong lịch sử Git File .env từng bị commit Xoay khóa, thêm .env vào .gitignore, dọn lịch sử bằng git filter-branch

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

Nếu khóa API CaptchaAI bị lộ, cần làm gì ngay?

Tạo khóa mới ngay trong bảng điều khiển CaptchaAI và cập nhật vào mọi ứng dụng đang dùng khóa cũ. Kiểm tra lịch sử số dư để xác nhận có bị dùng trái phép hay không trước khi vô hiệu hóa hẳn khóa cũ.

CaptchaAI có hỗ trợ giới hạn khóa API theo địa chỉ IP không?

Có — nếu bảng điều khiển tài khoản hiện tùy chọn giới hạn IP, hãy bật và chỉ đưa IP của server đang chạy job vào danh sách trắng.

Xoay khóa API bao lâu một lần là hợp lý?

Không có con số bắt buộc, nhưng xoay theo quý hoặc ngay khi có thành viên rời dự án là mốc hợp lý cho phần lớn team automation.

Có nên lưu khóa API trong GitHub Actions secrets thay vì file .env?

Nên. Secrets manager của nền tảng CI/CD, như GitHub Actions secrets, an toàn hơn file .env — vốn dễ bị commit nhầm.

Có nên copy khóa API vào Docker image để tiện triển khai không?

Không nên. Khóa nằm sẵn trong image sẽ lộ cho bất kỳ ai kéo được image đó. Truyền khóa qua biến môi trường lúc container khởi chạy, hoặc dùng Docker secrets cho production.


Hướng dẫn liên quan


Bảo vệ số dư của bạn — bật giới hạn IP và bảo mật khóa API CaptchaAI ngay hôm nay.

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