Một API key CaptchaAI nằm trong source code là một API key đã bị chia sẻ. Cách xử lý an toàn chỉ gồm ba việc: đặt key vào biến môi trường, đọc nó bằng os.environ (hoặc process.env), và xác thực key ngay khi tiến trình khởi động thay vì để job scraping chết giữa chừng lúc 2 giờ sáng.
Thứ tự bên dưới đi từ file .env trên máy local ra tới Docker và CI/CD.
Vì sao key không bao giờ nên nằm trong repo
Rủi ro thực tế không đến từ hacker mà từ quy trình hằng ngày. Một đội automation ở TP.HCM thường có nhiều dev cùng đọc repo, một bản fork nội bộ cho khách và một pipeline CI; key hardcode sẽ đi theo tất cả, rồi ở lại trong lịch sử Git kể cả khi bạn xóa dòng chứa nó. Với team outsourcing, tách credential khỏi source còn là điều kiện để bàn giao sạch: khách nhận repo mà không nhận luôn khóa của bạn.
Bước 1: file .env cho môi trường phát triển cục bộ
Tạo file .env ở thư mục gốc dự án:
CAPTCHAAI_API_KEY=your_actual_api_key_here
Thêm vào .gitignore ngay, trước commit đầu tiên chứ không phải sau:
# .gitignore
.env
.env.local
.env.production
Đọc key trong Python với python-dotenv
Cài thư viện:
pip install python-dotenv
load_dotenv() nạp file .env vào môi trường tiến trình, sau đó code chỉ làm việc với tên biến:
import os
from dotenv import load_dotenv
load_dotenv()
API_KEY = os.environ["CAPTCHAAI_API_KEY"]
# Use in API calls
import requests
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": "6Le-SITEKEY",
"pageurl": "https://example.com",
"json": "1",
})
print(resp.json())
Dùng os.environ[...] thay vì os.environ.get(...): thiếu biến thì chương trình dừng ngay tại dòng đó thay vì gửi request rỗng.
Đọc key trong Node.js với dotenv
npm install dotenv
Kiểm tra biến rỗng ngay đầu file — đây là chỗ tốn ít công nhất để phát hiện cấu hình sai:
require('dotenv').config();
const API_KEY = process.env.CAPTCHAAI_API_KEY;
if (!API_KEY) {
console.error('CAPTCHAAI_API_KEY not set');
process.exit(1);
}
// Use in API calls
const axios = require('axios');
const resp = await axios.post('https://ocr.captchaai.com/in.php', null, {
params: {
key: API_KEY,
method: 'userrecaptcha',
googlekey: '6Le-SITEKEY',
pageurl: 'https://example.com',
json: 1,
},
});
console.log(resp.data);
Bước 2: đặt biến ở cấp hệ điều hành
Trên máy chủ chạy job định kỳ, bạn có thể bỏ hẳn file .env: ít file hơn thì ít thứ để lỡ tay commit hơn.
Trên Linux và macOS:
export CAPTCHAAI_API_KEY="your_actual_api_key_here"
# Persist across sessions — add to ~/.bashrc or ~/.zshrc
echo 'export CAPTCHAAI_API_KEY="your_actual_api_key_here"' >> ~/.bashrc
Trên Windows, dùng PowerShell:
$env:CAPTCHAAI_API_KEY = "your_actual_api_key_here"
# Persist permanently
[System.Environment]::SetEnvironmentVariable("CAPTCHAAI_API_KEY", "your_actual_api_key_here", "User")
Lưu ý: biến đặt trong shell chỉ sống trong phiên hiện tại. Nếu job chạy qua cron hoặc systemd, hãy khai báo biến trong file service hoặc file môi trường riêng, vì cron không nạp ~/.bashrc.
Bốn sai lầm thường làm lộ key
| Sai lầm | Rủi ro | Cách xử lý |
|---|---|---|
Commit file .env lên Git |
Key ở lại trong lịch sử repo và mọi bản clone | Thêm .env vào .gitignore trước commit đầu tiên |
| Log nguyên giá trị key | Key lộ trong hệ thống log tập trung cả team đọc được | Chỉ log 4 ký tự cuối, hoặc bỏ hẳn dòng log đó |
| Hardcode key trong Dockerfile | Key nằm trong layer của image, ai pull image cũng đọc được | Truyền bằng ENV lúc chạy, không đặt ở build stage |
| Gửi key qua chat hoặc email | Key nằm lại trong lịch sử hội thoại, khó thu hồi | Dùng secret manager hoặc kênh chia sẻ có mã hóa |
Hay gặp nhất vẫn là dòng print(API_KEY) còn sót lại từ lúc debug và không ai để ý khi merge.
Bước 3: truyền key vào container Docker
Cách đơn giản nhất là truyền biến ngay lúc chạy container:
docker run -e CAPTCHAAI_API_KEY="your_key" my-scraper
Docker Compose
# docker-compose.yml
services:
scraper:
image: my-scraper
environment:
- CAPTCHAAI_API_KEY=${CAPTCHAAI_API_KEY}
${CAPTCHAAI_API_KEY} tham chiếu biến môi trường của máy host — key không bao giờ xuất hiện trong file compose, nên file này có thể commit bình thường.
Docker secrets (chế độ Swarm)
Trong Swarm, secret được mount thành file thay vì nằm ở biến môi trường:
echo "your_actual_api_key_here" | docker secret create captchaai_key -
# docker-compose.yml (Swarm mode)
services:
scraper:
image: my-scraper
secrets:
- captchaai_key
secrets:
captchaai_key:
external: true
Đọc trong code:
with open("/run/secrets/captchaai_key") as f:
API_KEY = f.read().strip()
Cách này kín hơn biến môi trường vì docker inspect không hiển thị nội dung secret.
Bước 4: khai báo secret trong CI/CD
GitHub Actions
# .github/workflows/scrape.yml
jobs:
scrape:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: python scraper.py
env:
CAPTCHAAI_API_KEY: ${{ secrets.CAPTCHAAI_API_KEY }}
Thêm secret tại Settings → Secrets and variables → Actions → New repository secret.
GitLab CI
# .gitlab-ci.yml
scrape:
script:
- python scraper.py
variables:
CAPTCHAAI_API_KEY: $CAPTCHAAI_API_KEY
Thêm biến tại Settings → CI/CD → Variables và bật tùy chọn "Masked" để giá trị bị che trong log build.
Bước 5: xác thực key ngay khi khởi động
Kiểm tra key trước khi pipeline gửi task đầu tiên. Một request getbalance tốn vài trăm mili giây và tránh cho bạn hàng loạt lỗi khó đọc giữa job:
import os
import sys
import requests
API_KEY = os.environ.get("CAPTCHAAI_API_KEY")
if not API_KEY:
print("ERROR: CAPTCHAAI_API_KEY environment variable not set")
sys.exit(1)
# Verify key works
resp = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "getbalance", "json": "1"
}).json()
if resp["status"] != 1:
print(f"ERROR: Invalid API key — {resp['request']}")
sys.exit(1)
print(f"API key valid — balance: ${float(resp['request']):.2f}")
Mã lỗi trả về là tiếng Anh (ERROR_WRONG_USER_KEY, ERROR_KEY_DOES_NOT_EXIST) — giữ nguyên trong log để tra cứu.
Quản lý key khi có nhiều môi trường và nhiều người
Một đội theo dõi giá trên các sàn thương mại điện tử thường chạy ba môi trường: máy dev, staging và job production hằng đêm. Giữ nguyên một tên biến CAPTCHAAI_API_KEY, chỉ đổi nguồn giá trị:
- Máy dev: file
.envcục bộ, không rời khỏi máy. - Staging và production: secret của CI/CD hoặc secret manager trên cloud (AWS Secrets Manager, Google Secret Manager, Azure Key Vault).
- Bàn giao cho khách: chỉ gửi
.env.examplevới giá trị rỗng.
Nhờ vậy code không cần biết nó đang chạy ở đâu, và khi cần thu hồi bạn chỉ xoay API key của một môi trường — kết hợp thêm IP whitelisting nếu job chạy từ IP cố định.
Câu hỏi thường gặp
Cả team có nên dùng chung một API key không?
Không nên. Mỗi môi trường một key riêng thì khi thu hồi một key, phần còn lại vẫn chạy, và nhìn lưu lượng là biết môi trường nào đang tiêu thụ.
Có nên commit file .env.example không?
Có. File .env.example chỉ chứa tên biến với giá trị rỗng, giúp người mới biết cần khai báo gì mà không lộ giá trị thật — miễn là .gitignore vẫn chặn .env.
Nếu key đã lỡ bị đẩy lên GitHub thì xử lý thế nào?
Xoay key ngay trong bảng điều khiển CaptchaAI, rồi mới dọn lịch sử Git. Xóa file và commit lại là chưa đủ: giá trị cũ vẫn nằm trong lịch sử repo và trong mọi bản clone đã tồn tại.
Tách key theo môi trường có làm tăng chi phí không?
Chi phí phụ thuộc vào gói bạn mua, không phụ thuộc vào số key. CaptchaAI tính giá theo thread (luồng giải đồng thời) với số lượt giải không giới hạn trong mỗi gói — ví dụ BASIC ($15/tháng, 5 thread) hay ADVANCE ($90/tháng, 50 thread). Điều cần cân nhắc là chia thread giữa các môi trường, không phải số lượng key.
Dùng nhiều API key trong một file .env như thế nào?
Khai báo một biến chứa danh sách phân tách bằng dấu phẩy, hoặc đánh số các biến:
CAPTCHAAI_KEYS=key1,key2,key3
keys = os.environ["CAPTCHAAI_KEYS"].split(",")
Sau đó chọn key theo môi trường hoặc theo worker khi khởi động tiến trình.
Bắt đầu với một tích hợp sạch
Lấy API key tại captchaai.com, đặt vào biến môi trường và chạy đoạn kiểm tra số dư ở Bước 5 trước lần deploy đầu tiên.