Bảo mật 02/09/2026 9 phút

Route đăng nhập không giới hạn = máy dò mật khẩu miễn phí: 2.600 lần thử trong 70 giây, và bốn cách bịt nó — cái nào cũng còn một khe hở

Một vòng lặp curl chạy chậm vẫn thử được 2.600 mật khẩu trong 70 giây khi route đăng nhập không chặn gì. Bốn chiến lược giới hạn kéo nó xuống 10, rồi 5 — nhưng mỗi cái mở ra một điểm mù riêng, trong đó có một khe hở biến chính lớp phòng thủ thành công cụ DoS.

Bảo mật 02/09/2026 9 phút

Mã TOTP sáu số của bạn không biết nó đang được gõ vào trang giả — và đó là lỗ hổng WebAuthn bịt bằng toán học

Tôi dựng TOTP thật rồi đo ba tính chất của nó: mã đổi mỗi 30 giây, cửa sổ chấp nhận ±31 giây, và tự nó KHÔNG chống phát lại. Nhưng điểm yếu chí mạng là phishing thời gian thực — thứ WebAuthn chặn được vì nó gắn chữ ký vào đúng tên miền. Hai công nghệ, hai triết lý.

Bảo mật 02/09/2026 9 phút

Không có PKCE, chỉ cần chặn được một mã là kẻ tấn công đổi được token của bạn — tôi đo đúng lỗ hổng đó trong 'Đăng nhập bằng Google'

Đo luồng authorization code của OAuth2: mã dùng một lần, redirect_uri khớp chính xác, và PKCE. Ba dòng cuối bảng đối xứng sáng tỏ — có PKCE thì chặn được mã vẫn vô dụng, không PKCE thì chặn được mã là chiếm được tài khoản. Vì sao authorization code + PKCE là luồng khuyến nghị cho MỌI ứng dụng.

Bảo mật 02/09/2026 9 phút

Đổi một con số trong URL, đọc thẻ tín dụng của người lạ — lỗ đứng đầu OWASP Top 10 chỉ là một câu if bị thiếu

IDOR: đăng nhập bằng tài khoản của mình, đổi /don/1 thành /don/2, và server ngoan ngoãn trả về đơn của người khác. Tôi đo lỗ này thật, và chứng minh vì sao id khó đoán (UUID) KHÔNG phải phân quyền — cách chặn duy nhất đúng là kiểm quyền sở hữu ở server.

Bảo mật 02/09/2026 9 phút

Tôi viết SELECT * FROM don_hang quên hẳn lọc quyền — và cơ sở dữ liệu vẫn chỉ trả về đúng đơn của người dùng đó, nhờ 3 câu SQL

IDOR là một câu if bị quên ở tầng ứng dụng, và bạn phải nhớ viết nó ở MỌI endpoint, mãi mãi. Row-Level Security của PostgreSQL đẩy phép kiểm quyền xuống chính bảng — nên cả một câu SELECT trần trụi không điều kiện cũng chỉ trả về dữ liệu người dùng được xem. Từ 'nhớ kiểm ở mọi nơi' thành 'định nghĩa một nơi, không thể bỏ qua'.

Bảo mật 02/09/2026 9 phút

Một tệp vừa là ảnh PNG thật (Pillow đọc được) vừa là mã PHP chạy được — và nó trả về uid=33 trên máy chủ của tôi

Cho tải tệp lên là một trong những tính năng nguy hiểm nhất. Tôi dựng một tệp 118 byte vừa mở ra thành PNG 1×1 hợp lệ, vừa thực thi lệnh trên máy chủ khi bị phục vụ nhầm. Bài học phản trực giác: 'kiểm xem có phải ảnh không' vô dụng, vì nó THẬT SỰ là ảnh.