# API của password.es đã phản hồi: dùng thế nào

> Một lệnh gọi không cần khóa, không cần đăng ký, trả về mật khẩu cùng đúng những con số bạn thấy trên trang: bit, thời gian bẻ khóa và mức độ. Kể cả những gì nó chưa làm được, và vì sao gọi nó không phải lúc nào cũng là ý hay.

2026-08-31 · David Carrero · password.es
Original: https://password.es/vi/blog/api-tao-mat-khau/

---

Blog này đã nhiều tháng lặp lại một điều: [mật khẩu của bạn không nên rời khỏi
trình duyệt](/vi/blog/tai-sao-chung-toi-khong-gui-mat-khau-cua-ban/). [Trình tạo
mật khẩu](/vi/) lấy tính ngẫu nhiên từ `crypto.getRandomValues()` ngay trên máy
của bạn, còn [trình kiểm tra](/vi/kiem-tra/) phân tích những gì bạn gõ mà không
gửi đi đâu cả.

Và hôm nay chúng tôi công bố một API tạo mật khẩu trên máy chủ.

**Mâu thuẫn là rõ ràng và chúng tôi sẽ không che đậy**: mỗi phản hồi của API đều
mang một lời cảnh báo nói đúng điều đó. Nhưng có những chỗ không có trình duyệt
— một script tạo một trăm tài khoản, một máy chủ sinh thông tin đăng nhập tạm
thời, một trợ lý bị ai đó hỏi xin mật khẩu và tự bịa ra — và ở đó, lựa chọn thay
thế không phải là «trình duyệt»: đó là một `random()` chọn sai hoặc một chuỗi gõ
bằng tay. API này sinh ra cho việc đó.

## Toàn bộ lệnh gọi

Không khóa, không đăng ký, không tiêu đề. Chỉ có vậy:

`curl -X POST https://api.password.es/v1/generate`

Nó trả về một mật khẩu 16 ký tự cùng phần phân tích. Chạy trong lúc viết đoạn
này: `x*7$9,BUy9PPvOI?`, lấy từ bảng chữ cái 89 ký tự, **103,6 bit** entropy và
thời gian bẻ khóa 2,5 × 10¹¹ năm. Mức 4 trên 4.

Không con số nào trong đó là mới. Chúng đến từ đúng bộ máy vẽ thanh đo ở trang
chủ: cùng công thức [bit](/vi/blog/bit-entropy-la-gi/), cùng mô hình tấn công —
10¹² lần đoán mỗi giây, ngoại tuyến, hàm băm nhanh — và cùng thang mức độ với
trình kiểm tra. Nếu trang web và API cho ra những con số khác nhau cho cùng một
mật khẩu thì một trong hai đang nói dối.

## Nó trả về gì, từng trường một

Phản hồi mang `passwords` — luôn là một mảng, kể cả khi bạn chỉ xin một — và một
khối `analysis` gồm `length`, `pool`, `bits`, `log10_guesses`,
`crack_time_log10_seconds`, `crack_time`, `level`, `level_scale` và `ceiling`.

Hai trong số đó đáng một đoạn riêng. **`level_scale` cho biết mức độ đến từ đâu**
(hiện luôn là `"time"`), để nếu sau này trang web và API lệch nhau thì điều đó
hiện ra ngay ở trường dữ liệu thay vì phải suy ra bằng cách so sánh các con số.
Còn **`ceiling` cho biết con số là chính xác hay chỉ là mức trần**: trong
`generate` nó luôn là `false`, vì mật khẩu do máy chủ tạo ra và nó biết dùng
bảng chữ cái nào; ở trình kiểm tra trên web thì không phải lúc nào cũng vậy, vì
ở đó mật khẩu là do bạn mang tới.

Sau đó là `notice`, lời cảnh báo, và một khối `_meta` với gói dịch vụ, ngôn ngữ
đã áp dụng, các giới hạn và một liên kết về tài liệu.

## Các tùy chọn

Tất cả đều không bắt buộc, và tên để nguyên tiếng Anh vì người tích hợp một API
sẽ gõ y hệt tên trường: `length` (4–64, mặc định 16), `count` (1–20), `lower`,
`upper`, `digits`, `symbols`, `exclude_ambiguous`, `no_repeats` và `lang`.

`curl -X POST https://api.password.es/v1/generate -H 'content-type: application/json' -d '{"length":20,"exclude_ambiguous":true}'`

Hai chi tiết mà tài liệu có nói và nên biết trước khi tích hợp.
**`exclude_ambiguous` bỏ sáu ký tự chứ không phải bảy**: nó loại `0 O 1 I l | o`,
nhưng dấu gạch đứng vốn không có trong bộ ký hiệu ngay từ đầu, nên bảng chữ cái
giảm từ 89 xuống 83 chứ không phải 82. Vì vậy phản hồi ghi `pool` là 83. Và
**`no_repeats` không phải là bảo đảm tuyệt đối**: nó thử lại mười lần, y như
trình tạo trên web, và ở 64 ký tự thì một cặp lặp liền kề vẫn lọt qua khoảng
0,1 % số lần. Nói ra như vậy hữu ích hơn là hứa điều ngược lại.

## Ngôn ngữ

Mặc định nó trả lời bằng tiếng Anh, đúng như người tích hợp mà không nói gì sẽ
mong đợi. Đổi bằng `?lang=` trên URL, bằng `"lang"` trong thân yêu cầu hoặc bằng
tiêu đề `Accept-Language`, và nếu mâu thuẫn thì cái đầu tiên thắng. Một ngôn ngữ
không tồn tại không phải là lỗi: nó rơi về tiếng Anh.

Ở đây có một sự bất đối xứng không thể đoán ra, và vì thế API tự khai báo:
**thông điệp có tiếng Anh và tiếng Tây Ban Nha; còn liên kết thì có đủ mười tám
ngôn ngữ của trang**. Xin tiếng Đức sẽ cho bạn liên kết tiếng Đức và thông điệp
vẫn bằng tiếng Anh. Không cần phải đoán: `_meta.lang` mang
`{ "messages", "links" }` cho biết mỗi nửa đã được áp dụng gì.

## Máy chủ MCP

MCP là giao thức để một trợ lý — Claude, ChatGPT — dùng công cụ bên ngoài.
`https://api.password.es/mcp` là một máy chủ MCP không đăng ký và không khóa, và
nó công bố đúng một công cụ: `generate_password`, với các tham số như trên.

Đây là phần chúng tôi quan tâm nhất, và không phải vì lý do kỹ thuật: **một trợ
lý không có chỗ nào để lấy mật khẩu sẽ tự bịa ra**, và thứ ra đời từ đó không hề
ngẫu nhiên, nó là thứ mà mô hình cho là trông giống mật khẩu. Khi nối máy chủ
này, trợ lý thôi ứng biến và trả về một mật khẩu tạo bằng
`crypto.getRandomValues()`, kèm phân tích và kèm lời cảnh báo nằm trong mô tả
công cụ lẫn trong từng kết quả. Chính lời cảnh báo đó là thứ trợ lý cuối cùng
đọc lại cho người đã hỏi xin mật khẩu, và đó là lý do nó có mặt.

Nếu bạn đến từ các máy chủ MCP khác, một điều thôi: **máy chủ này không có trạng
thái.** POST được trả lời bằng JSON và không mở luồng nào, `Mcp-Session-Id`
không được phát ra cũng không được chờ đợi, một thông báo nhận về 202 không có
thân, và GET trả về 405. Đặc tả 2025-06-18 cho phép điều đó một cách rõ ràng,
nhưng ai chờ phiên làm việc và SSE sẽ gỡ lỗi trong mù mờ nếu không ai nói.

## Những gì nó không làm

**`/v1/check` trả về 501.** Đó không phải sơ suất hay một endpoint làm dở: nó cố
ý như vậy, và chính phản hồi giải thích vì sao. Trả về đúng những con số của
trình kiểm tra đòi hỏi đúng bộ máy nhận dạng mẫu đang chạy trên web, và bộ máy
đó tốn từ 11 ms đến 3,6 giây CPU mỗi yêu cầu tùy vào thứ được gửi lên. Với một
dịch vụ không đăng ký và không khóa, khoảng chênh đó là một quyết định sản phẩm
— đặt trần độ dài ở đâu — và vẫn chưa được chốt. Trong lúc chờ, mã 501 mang theo
`checker_url` trỏ tới trình kiểm tra trên web bằng đúng ngôn ngữ bạn yêu cầu,
nơi làm đúng việc này mà không gửi gì đi.

Tài khoản cũng chưa có, khóa cũng không, gói cước cũng không. Và vì chúng không
tồn tại, trong toàn bộ API không có lấy một liên kết đăng ký nào: kể cả trong
lỗi vượt giới hạn, chỗ mà ai cũng đặt một cái.

## Các giới hạn

Một cái, và đó là cái thực sự được áp dụng: **60 yêu cầu mỗi phút cho mỗi IP**.
Không cần tin trang này: con số đi kèm trong từng phản hồi, ở
`_meta.limits.burst`. Vượt quá thì nhận 429 kèm `Retry-After` và các tiêu đề
`RateLimit-*`.

Trong `_meta` bạn còn thấy khối `quota` với các giá trị `null`. Đó là chỗ dành
sẵn cho khi nào có tài khoản, và nó để trống một cách có chủ ý: **một giới hạn
được công bố mà không được thi hành còn tệ hơn là không công bố gì**, vì người
tích hợp sẽ tôn trọng nó và lập trình theo một con số chẳng ai đếm.

## Và dù vậy, hãy cân nhắc hai lần

Một API tạo mật khẩu, xét cho cùng, là một phản mẫu: mật khẩu đi qua mạng và đi
qua một cái máy không phải của bạn. Việc chúng tôi không lưu gì không làm thay
đổi hình dạng của vấn đề, chỉ thay đổi phần của chúng tôi trong đó — và bạn đã
biết [một lời hứa không kiểm chứng được thì đáng giá bao
nhiêu](/vi/blog/tai-sao-chung-toi-khong-gui-mat-khau-cua-ban/).

Vì thế lời cảnh báo không chỉ sống trên trang này: nó đi theo từng phản hồi,
bằng ngôn ngữ bạn yêu cầu. Và vì thế đoạn văn này nằm ở đây chứ không giấu ở
cuối tài liệu. **Với một mật khẩu bạn sẽ tự dùng, [trình tạo](/vi/) của trang
này chạy hoàn toàn trong trình duyệt của bạn và không gửi gì đi.** API là cho
việc khác: cho những gì diễn ra khi không có ai ngồi trước màn hình.

Chi tiết nằm ở hai trang. [API là gì](/vi/api/) kể nó dành cho ai, hôm nay cái
gì phản hồi và cái gì không. [Tài liệu tham khảo](/vi/api/docs/) có đủ chín tham
số, mọi trường được giải thích từng cái một, các mã lỗi và các giới hạn; đó là
trang bạn mở cạnh trình soạn thảo. Còn nếu bạn muốn máy đọc nó, đã có
`openapi.json`.

---

*Nguồn: chính API đó, đã kiểm chứng trên môi trường thật ngày 31 tháng 8 năm
2026 — `POST /v1/generate`, `POST /v1/check` (501), `POST /mcp` và
`GET /openapi.json` · các con số phân tích đến từ cùng bộ máy với trình tạo và
trình kiểm tra của password.es · mô hình tấn công là 10¹² lần đoán mỗi giây,
ngoại tuyến và với hàm băm nhanh, giống phần còn lại của trang · máy chủ MCP
triển khai đặc tả 2025-06-18 với truyền tải Streamable HTTP không trạng thái.*
