Một đêm bị spam tin nhắn, sáng ra bill AI vài trăm đô
Chatbot hay tính năng AI trong app mà không có trần chi phí thì chỉ cần một script gửi tin liên tục cả đêm. Cách đặt trần theo người dùng, theo ngày ngay trong code, và bật giới hạn cứng trên trang của OpenAI, Anthropic, Google.
Xem nhanh trong 1 phút
Chatbot trên trang của bạn trả lời khách bằng API của OpenAI hay Claude. Mỗi tin nhắn tốn một ít tiền, ít tới mức không ai để ý. Rồi một đêm có người viết script gửi tin liên tục, mỗi tin dán thêm vài trang văn bản cho dài. Không cần chiếm key, không cần lỗ hổng gì. Họ chỉ dùng đúng cái ô chat bạn mở sẵn.
OWASP gọi kiểu này là Denial of Wallet, nằm trong mục LLM10:2025 Unbounded Consumption của danh sách rủi ro cho ứng dụng LLM. Mục tiêu không phải làm sập app mà làm cạn ví của bạn.
Tiền chảy ra nhanh cỡ nào
Tính thử với con số giả định: giá 3 đô cho một triệu token đầu vào, mỗi tin nhắn kèm lịch sử chat và văn bản dán vào khoảng 8.000 token. Một script gửi 20.000 tin trong một đêm là 160 triệu token, tức khoảng 480 đô, chưa tính token đầu ra. Giá thật của từng model khác nhau, bạn thay vào là ra con số của mình.
Chỗ nguy hiểm là app vibe code thường gửi cả lịch sử hội thoại lên mỗi lần, nên cuộc chat càng dài thì mỗi tin càng đắt. Người dùng bình thường không chat tới tin thứ 500. Script thì có.
Lớp 1: giới hạn ngay trên trang của nhà cung cấp
Làm việc này trước, mất năm phút, và nó là lưới cuối cùng khi code của bạn có lỗi.
OpenAI: vào Project settings, mục Limits, phần Spend, bấm Edit spend limit, nhập hạn mức tháng và bật “Enforce a hard limit”. Chạm trần thì API trả lỗi 429 với mã project_spend_limit_exceeded. Tài liệu của OpenAI nói rõ việc chặn không tức thì, số tiền ghi nhận có thể vượt trần một chút. Đặt thêm spend alert ở mức thấp hơn để có email báo trước.
Anthropic (Claude Console): tổ chức và từng workspace có spend limit theo tháng. Tách app thật ra một workspace riêng, đặt trần riêng cho nó, để một app bị spam không ăn hết hạn mức của cả công ty.
Google Cloud (Gemini API): budget thông thường chỉ gửi cảnh báo, tài liệu của Google ghi rõ nó không tự chặn chi tiêu. Muốn chặn thật thì dùng spend cap budget cho project nếu dịch vụ của bạn hỗ trợ; khi chạm trần, dịch vụ bị tạm dừng tới lúc bạn tự gỡ.
Mỗi app một project hay workspace, mỗi project một key. Như vậy trần đặt ra mới có nghĩa.
Lớp 2: trần theo người dùng, theo ngày trong code
Trần của nhà cung cấp chặn cả app. Khi nó chạm trần, mọi khách đều mất chatbot, kể cả người dùng thật. Vì vậy cần thêm một lớp nhỏ hơn: mỗi tài khoản (hoặc mỗi IP với khách chưa đăng nhập) chỉ được tiêu tối đa một số tiền mỗi ngày.
Ý tưởng giống thẻ điện thoại trả trước. Trước mỗi lần gọi model, kiểm tra còn bao nhiêu trong thẻ. Sau khi gọi xong, trừ đúng số token đã dùng.
-- Postgres / Supabasecreate table ai_usage ( user_id text not null, day date not null default current_date, cost_micro bigint not null default 0, -- đơn vị: phần triệu đô primary key (user_id, day));
// Next.js route handler, ví dụ với OpenAI SDKconst DAILY_LIMIT_MICRO = 200_000 // 0,2 đô mỗi người mỗi ngày, tự chọn theo appconst PRICE_IN = 3, PRICE_OUT = 15 // micro-đô mỗi token, lấy từ trang giá của model bạn dùngexport async function POST(req: Request) { const user = await requireUser(req) const { message } = await req.json() if (typeof message !== 'string' || message.length > 4000) return new Response('Tin quá dài', { status: 413 }) const spent = await getSpentToday(user.id) if (spent >= DAILY_LIMIT_MICRO) { return new Response('Hôm nay bạn đã dùng hết lượt, mai quay lại nhé', { status: 429, headers: { 'Retry-After': '3600' } }) } const history = await lastMessages(user.id, 10) // chỉ gửi 10 tin gần nhất, không gửi cả lịch sử const res = await openai.chat.completions.create({ model: MODEL, max_completion_tokens: 500, // chặn câu trả lời dài vô tận messages: [...history, { role: 'user', content: message }], }) const u = res.usage! await addSpent(user.id, u.prompt_tokens * PRICE_IN + u.completion_tokens * PRICE_OUT) return Response.json({ reply: res.choices[0].message.content })}
addSpent nên là một câu insert ... on conflict (user_id, day) do update set cost_micro = ai_usage.cost_micro + $2 để không bị lệch khi hai request chạy cùng lúc. Với Claude thì số token nằm ở usage.input_tokens và usage.output_tokens.
Ba giới hạn nhỏ trong đoạn code trên đáng tiền hơn bạn nghĩ: độ dài tin nhắn, số tin lịch sử gửi lên, và max_completion_tokens. Chúng chặn chiêu “mỗi tin dán một cuốn sách”.
Lớp 3: cảnh báo khi gần trần
Chạm trần mới biết thì đã muộn một nửa. Thêm hai cảnh báo:
Tổng chi của cả app trong ngày vượt 50% hoặc 80% mức bạn chịu được thì nhắn Telegram hay gửi email cho bạn. Một cron 15 phút cộng bảng ai_usage là đủ.
Một tài khoản chạm trần ngày ba hôm liên tiếp, hoặc tạo hàng chục tài khoản từ cùng một IP, thì đánh dấu để xem tay.
Kết hợp với rate limit thông thường (ví dụ 10 tin mỗi phút mỗi người) nữa là script spam hết đường chạy cả đêm.
Kiểm tra app của bạn trong vài phút
Mở trang billing của nhà cung cấp AI bạn dùng. Có hard limit chưa, hay chỉ có cảnh báo? Key của app đang nằm trong project hay workspace nào?
Tìm trong code chỗ gọi model (chat.completions.create, messages.create, generateContent). Có max_tokens không? Có cắt bớt lịch sử không? Có kiểm độ dài tin nhắn không?
Đăng xuất, mở ô chat. Khách chưa đăng nhập có gọi được AI không? Nếu có, giới hạn theo IP đang ở đâu?
Thử gửi 30 tin liên tục bằng một vòng lặp curl. Nếu tin thứ 30 vẫn được trả lời bình thường, app chưa có rate limit.
App của bạn đã từng bị một đêm bill AI tăng vọt chưa, và lúc đó bạn phát hiện bằng cách nào? Vào cộng đồng Vibe Code & Bảo Mật kể cho mọi người nghe nhé.
API keychi phí AIchatbot/anh/web/tran-chi-phi-ai-cho-app-480.webpAPI key · chi phí AI · chatbot
Mot dem bi spam tin nhan, sang ra bill AI vai tram do Chatbot hay tinh nang AI trong app ma khong co tran chi phi thi chi can mot script gui tin lien tuc ca dem. Cach dat tran theo nguoi dung, theo ngay ngay trong code, va bat gioi han cung tren trang cua OpenAI, Anthropic, Google. API key chi phi AI chatbot Chatbot tren trang cua ban tra loi khach bang API cua OpenAI hay Claude. Moi tin nhan ton mot it tien, it toi muc khong ai de y. Roi mot dem co nguoi viet script gui tin lien tuc, moi tin dan them vai trang van ban cho dai. Khong can chiem key, khong can lo hong gi. Ho chi dung dung cai o chat ban mo san.
OWASP goi kieu nay la Denial of Wallet, nam trong muc LLM10:2025 Unbounded Consumption cua danh sach rui ro cho ung dung LLM. Muc tieu khong phai lam sap app ma lam can vi cua ban.

## Tien chay ra nhanh co nao
Tinh thu voi con so gia dinh: gia 3 do cho mot trieu token dau vao, moi tin nhan kem lich su chat va van ban dan vao khoang 8.000 token. Mot script gui 20.000 tin trong mot dem la 160 trieu token, tuc khoang 480 do, chua tinh token dau ra. Gia that cua tung model khac nhau, ban thay vao la ra con so cua minh.
Cho nguy hiem la app vibe code thuong gui **ca lich su hoi thoai** len moi lan, nen cuoc chat cang dai thi moi tin cang dat. Nguoi dung binh thuong khong chat toi tin thu 500. Script thi co.
## Lop 1: gioi han ngay tren trang cua nha cung cap
Lam viec nay truoc, mat nam phut, va no la luoi cuoi cung khi code cua ban co loi.
- **OpenAI**: vao Project settings, muc Limits, phan Spend, bam Edit spend limit, nhap han muc thang va bat "Enforce a hard limit". Cham tran thi API tra loi 429 voi ma `project_spend_limit_exceeded`. Tai lieu cua OpenAI noi ro viec chan khong tuc thi, so tien ghi nhan co the vuot tran mot chut. Dat them spend alert o muc thap hon de co email bao truoc.
- **Anthropic (Claude Console)**: to chuc va tung workspace co spend limit theo thang. Tach app that ra mot workspace rieng, dat tran rieng cho no, de mot app bi spam khong an het han muc cua ca cong ty.
- **Google Cloud (Gemini API)**: budget thong thuong **chi gui canh bao**, tai lieu cua Google ghi ro no khong tu chan chi tieu. Muon chan that thi dung spend cap budget cho project neu dich vu cua ban ho tro; khi cham tran, dich vu bi tam dung toi luc ban tu go.
Moi app mot project hay workspace, moi project mot key. Nhu vay tran dat ra moi co nghia.
## Lop 2: tran theo nguoi dung, theo ngay trong code
Tran cua nha cung cap chan ca app. Khi no cham tran, moi khach deu mat chatbot, ke ca nguoi dung that. Vi vay can them mot lop nho hon: moi tai khoan (hoac moi IP voi khach chua dang nhap) chi duoc tieu toi da mot so tien moi ngay.
Y tuong giong the dien thoai tra truoc. Truoc moi lan goi model, kiem tra con bao nhieu trong the. Sau khi goi xong, tru dung so token da dung.
```sql
-- Postgres / Supabase
create table ai_usage (
user_id text not null,
day date not null default current_date,
cost_micro bigint not null default 0, -- don vi: phan trieu do
primary key (user_id, day)
);
```
```ts
// Next.js route handler, vi du voi OpenAI SDK
const DAILY_LIMIT_MICRO = 200_000 // 0,2 do moi nguoi moi ngay, tu chon theo app
const PRICE_IN = 3, PRICE_OUT = 15 // micro-do moi token, lay tu trang gia cua model ban dung
export async function POST(req: Request) {
const user = await requireUser(req)
const { message } = await req.json()
if (typeof message !== 'string' || message.length > 4000) return new Response('Tin qua dai', { status: 413 })
const spent = await getSpentToday(user.id)
if (spent >= DAILY_LIMIT_MICRO) {
return new Response('Hom nay ban da dung het luot, mai quay lai nhe', { status: 429, headers: { 'Retry-After': '3600' } })
}
const history = await lastMessages(user.id, 10) // chi gui 10 tin gan nhat, khong gui ca lich su
const res = await openai.chat.completions.create({
model: MODEL,
max_completion_tokens: 500, // chan cau tra loi dai vo tan
messages: [...history, { role: 'user', content: message }],
})
const u = res.usage!
await addSpent(user.id, u.prompt_tokens * PRICE_IN + u.completion_tokens * PRICE_OUT)
return Response.json({ reply: res.choices[0].message.content })
}
```
`addSpent` nen la mot cau `insert ... on conflict (user_id, day) do update set cost_micro = ai_usage.cost_micro + $2` de khong bi lech khi hai request chay cung luc. Voi Claude thi so token nam o `usage.input_tokens` va `usage.output_tokens`.
Ba gioi han nho trong doan code tren dang tien hon ban nghi: do dai tin nhan, so tin lich su gui len, va `max_completion_tokens`. Chung chan chieu "moi tin dan mot cuon sach".
## Lop 3: canh bao khi gan tran
Cham tran moi biet thi da muon mot nua. Them hai canh bao:
- Tong chi cua ca app trong ngay vuot 50% hoac 80% muc ban chiu duoc thi nhan Telegram hay gui email cho ban. Mot cron 15 phut cong bang `ai_usage` la du.
- Mot tai khoan cham tran ngay ba hom lien tiep, hoac tao hang chuc tai khoan tu cung mot IP, thi danh dau de xem tay.
Ket hop voi rate limit thong thuong (vi du 10 tin moi phut moi nguoi) nua la script spam het duong chay ca dem.
## Kiem tra app cua ban trong vai phut
1. Mo trang billing cua nha cung cap AI ban dung. Co hard limit chua, hay chi co canh bao? Key cua app dang nam trong project hay workspace nao?
2. Tim trong code cho goi model (`chat.completions.create`, `messages.create`, `generateContent`). Co `max_tokens` khong? Co cat bot lich su khong? Co kiem do dai tin nhan khong?
3. Dang xuat, mo o chat. Khach chua dang nhap co goi duoc AI khong? Neu co, gioi han theo IP dang o dau?
4. Thu gui 30 tin lien tuc bang mot vong lap `curl`. Neu tin thu 30 van duoc tra loi binh thuong, app chua co rate limit.
---
App cua ban da tung bi mot dem bill AI tang vot chua, va luc do ban phat hien bang cach nao? Vao [cong dong Vibe Code & Bao Mat](https://www.facebook.com/groups/1867387324580254) ke cho moi nguoi nghe nhe.
## Nguon
- [LLM10:2025 Unbounded Consumption](https://genai.owasp.org/llmrisk/llm102025-unbounded-consumption/), OWASP GenAI Security Project
- [Spend limits](https://developers.openai.com/api/docs/guides/spend-limits), OpenAI
- [Set Spend Limit](https://platform.claude.com/docs/en/api/admin/spend_limits/create.md), Anthropic
- [Create, edit, or delete budgets and budget alerts](https://docs.cloud.google.com/billing/docs/how-to/budgets), Google Cloud