Cách dùng WAF và Rate Limiting để bảo vệ wp-login.php

Minh họa WAF và Rate Limiting bảo vệ wp-login.php khỏi brute force và credential stuffing

wp-login.php là một trong những endpoint WordPress bị brute-force và credential-stuffing nhắm tới nhiều nhất vì nó public, quen thuộc và kích hoạt toàn bộ flow xác thực của WordPress. Khi request được gửi với tần suất cao, ngay cả đăng nhập thất bại cũng có thể tiêu tốn PHP worker, database query và tài nguyên application.

WAF và Rate Limiting giúp giảm tải trước khi request chạm sâu vào WordPress, nhưng không thay thế password mạnh, MFA, passkey, account policy hoặc patch. Mục tiêu là giảm automation độc hại mà vẫn giữ trải nghiệm đăng nhập hợp lệ, không phải đặt một ngưỡng thật thấp rồi block tất cả.

Brute force, credential stuffing và login flood khác nhau ở đâu?

Kiểu abuseĐặc điểmControl hữu ích
Brute forceThử nhiều password cho một hoặc vài accountRate limit, MFA, password policy
Credential stuffingDùng credential đã rò rỉ để thử trên nhiều accountRate limit, bot detection, MFA/passkey
Login floodGửi lượng lớn request vào login để làm cạn tài nguyênEdge rate limit, WAF/CDN, origin protection

WordPress Advanced Administration hiện khuyến nghị rate-limit login ở edge/WAF/CDN hoặc web server, dùng MFA/passkeys và theo dõi authentication anomaly. Nếu chỉ throttle bằng plugin chạy trong PHP, request vẫn đã tới application và vẫn tiêu tốn một phần tài nguyên.

Thiết kế rate-limit policy

Bảo vệ đúng path: GET và POST không giống nhau

Request GET tới /wp-login.php thường chỉ tải form đăng nhập; POST mới thực hiện xác thực. Nếu mục tiêu là giảm brute-force, việc đếm riêng POST thường chính xác hơn so với tính mọi request tới login page.

  • GET /wp-login.php: nên hạn chế challenge/block quá mạnh vì user thật cần tải form.
  • POST /wp-login.php: phù hợp để rate-limit theo tần suất xác thực.
  • Response failure: nếu nền tảng hỗ trợ counting expression theo response code, có thể ưu tiên đếm các lần xác thực thất bại.
  • Successful login: không nên bị tính giống hàng loạt failed attempt nếu có thể phân biệt.

Cloudflare hiện có ví dụ credential-stuffing dùng expression theo hostname + login path + POST method, sau đó áp penalty tăng dần. Tuy nhiên threshold trong tài liệu chỉ là ví dụ; cần điều chỉnh theo traffic thật của site.

Không dùng một threshold cố định cho mọi website

Một site membership, WooCommerce hoặc multisite có thể có hành vi login khác hẳn blog nhỏ. Threshold nên được lấy từ baseline và attack telemetry:

  • bao nhiêu POST login/IP trong giờ bình thường;
  • bao nhiêu failed login liên tiếp là phổ biến với user thật;
  • có office NAT khiến nhiều user dùng chung một IP không;
  • mobile carrier/VPN có tạo shared IP không;
  • peak login xảy ra khi nào;
  • SSO, app mobile hoặc integration có đi qua cùng endpoint không.

Cloudflare cũng khuyến nghị xác định rate limit từ traffic analytics của chính endpoint thay vì chọn ngưỡng tùy ý. Baseline phải được quan sát cả lúc bình thường lẫn lúc bị abuse.

Mô hình rate limiting theo tầng

Một chiến lược thực tế là tăng dần mức phản ứng thay vì block ngay từ lần vượt đầu tiên:

  1. Quan sát: log/count các POST tới login để lấy baseline.
  2. Challenge nhẹ: khi tần suất vượt baseline ngắn hạn.
  3. Penalty mạnh hơn: nếu cùng client tiếp tục failed attempts trong khoảng thời gian dài hơn.
  4. Block tạm thời: chỉ khi confidence đủ cao và đã test false positive.

Tiered rate limiting đặc biệt hữu ích với credential stuffing vì bot có thể chậm lại để né một ngưỡng đơn. Dù vậy, IP không phải identity hoàn hảo; distributed botnet có thể chia traffic qua nhiều source.

Managed Challenge hay Block?

Với browser login, challenge có thể cho user thật vượt qua khi vô tình chạm threshold. Block cho false positive hậu quả lớn hơn. Vì vậy với rule mới, challenge hoặc log/count thường an toàn hơn block trực tiếp.

Tuy nhiên challenge không phù hợp mọi flow. Cloudflare lưu ý challenge cần HTML response để render; AJAX/XHR hoặc API-based login có thể bị gián đoạn. Nếu WordPress site dùng headless login, custom frontend hoặc API auth, cần test riêng thay vì áp challenge sitewide.

WAF Rule nên match những gì?

  • hostname chính xác;
  • URI path bằng /wp-login.php;
  • method POST nếu mục tiêu là authentication attempts;
  • có thể thêm bot/risk signal nếu nền tảng hỗ trợ;
  • không dùng user-agent đơn lẻ làm căn cứ block;
  • tránh country block nếu không có business requirement/evidence.

Rule càng rõ scope càng dễ debug. Nếu muốn xem anatomy, order và lifecycle của rule, đọc WAF Rule là gì?.

Rủi ro false positive với shared IP

Nhiều người dùng có thể chia sẻ một IP qua NAT, office gateway, mobile carrier hoặc VPN. Nếu rate limit chỉ đếm theo IP và threshold quá thấp, một nhóm user hợp lệ có thể bị challenge/block cùng lúc. Khi nghi ngờ chặn nhầm, dùng quy trình điều tra WAF false positive để xác minh event, rule và scope trước khi mở exception.

Nếu nền tảng hỗ trợ counting characteristics tốt hơn như session, cookie, JA3/JA4 hoặc account context, có thể cân nhắc kết hợp. Nhưng bất kỳ signal nào cũng cần test với privacy và traffic thực tế.

Các control bổ sung quanh login

Đừng quên XML-RPC nếu site còn dùng

xmlrpc.php từng là mục tiêu phổ biến cho brute-force và abuse. WordPress hiện khuyến nghị nếu không dùng XML-RPC thì cân nhắc disable; nếu còn dùng cho Jetpack, mobile app hoặc integration thì nên restrict/rate-limit thay vì block mù.

Không nên copy rule của wp-login.php sang xmlrpc.php mà không hiểu client. XML-RPC là machine-to-machine flow; interactive challenge có thể làm integration hỏng.

MFA và Rate Limiting giải quyết hai vấn đề khác nhau

Rate limiting giảm tốc độ automation và tải lên origin. MFA/passkey giảm khả năng account takeover ngay cả khi password đã bị lộ. Hai lớp này bổ sung nhau:

  • Rate limit không ngăn một credential đúng được dùng ngay lần đầu.
  • MFA không ngăn bot gửi hàng nghìn request làm tốn tài nguyên.
  • WAF không sửa password reuse hoặc account policy.
  • Plugin login security không thay protection ở edge khi attack volume lớn.

Khi nào nên allowlist?

Allowlist có thể phù hợp cho một office IP cố định hoặc monitoring/integration đã xác minh, nhưng không nên dùng để né tuning cho user bình thường. Nếu allowlist, cần biết chính xác protection nào bị skip và review khi source network thay đổi.

Rollout và vận hành

Quy trình rollout an toàn

  1. Lấy baseline POST tới wp-login.php.
  2. Phân biệt traffic normal, admin office, bot và attack window.
  3. Tạo rule ở log/count mode.
  4. Review top IP/source và failed login pattern.
  5. Chọn threshold ban đầu bảo thủ.
  6. Ưu tiên challenge trước block nếu browser flow phù hợp.
  7. Test desktop, mobile, MFA, password reset và SSO nếu có.
  8. Theo dõi login success rate, 403/429/challenge và support ticket.
  9. Tune threshold sau khi có đủ traffic.
  10. Document rollback và owner.

Metric nên theo dõi

  • POST /wp-login.php per minute;
  • failed login per source/client;
  • successful login rate;
  • challenge solve/fail rate;
  • 429/403 response count;
  • PHP worker/CPU trước và sau khi rate limit;
  • unique source IP/ASN;
  • XML-RPC request volume nếu endpoint còn bật;
  • support ticket về login;
  • account-lockout hoặc reset-password spike.

Sai lầm thường gặp

  • dùng threshold cực thấp sao chép từ tutorial;
  • rate-limit cả GET và POST như nhau;
  • block ngay thay vì quan sát;
  • challenge XML-RPC/API machine traffic;
  • coi IP là identity tuyệt đối;
  • không test password reset/MFA;
  • không theo dõi false positive;
  • chỉ bảo vệ login nhưng bỏ qua XML-RPC đang sử dụng;
  • không có MFA/passkey vì nghĩ WAF đã đủ.

Checklist triển khai cho wp-login.php

  • Endpoint login thực tế đã được xác nhận?
  • POST được tách khỏi GET?
  • Baseline login traffic đã có?
  • Shared IP/NAT đã được cân nhắc?
  • Rule chạy ở log/count trước?
  • Action có phù hợp browser/API flow?
  • MFA/passkey đã được triển khai cho admin?
  • XML-RPC có cần dùng không?
  • Telemetry đủ để thấy false positive?
  • Rollback đã được chuẩn bị?

Nếu cần kiểm thử rule trước production, xem Cách triển khai WAF cho website mà không làm lỗi chức năng. Rule và threshold vẫn phải được điều chỉnh theo platform và baseline thực tế, không copy nguyên ngưỡng sang production.

Kết luận

Bảo vệ wp-login.php tốt nhất là phối hợp WAF/rate limiting ở edge với MFA/passkey, password hygiene và monitoring. Hãy rate-limit đúng POST authentication flow, lấy threshold từ baseline và rollout từ observe tới challenge/block thay vì dùng một con số cố định cho mọi site.

Nếu login abuse là một phần của HTTP flood rộng hơn, cần chuyển sang phân tích Layer 7 DDoS và origin capacity thay vì chỉ tiếp tục giảm threshold trên một endpoint.

Nguồn tham khảo

◇
Cần hỗ trợ kiểm tra và xử lý website?Đội ngũ SecureWebOps sẵn sàng hỗ trợ theo phạm vi phù hợp.
Liên hệ ngay →
Đoàn Trình Dục
Về tác giả Đoàn Trình Dục TD Digital · Website Operations & Security

Đoàn Trình Dục là tác giả nội dung trên SecureWebOps. Các bài viết tập trung vào bảo mật WordPress, giám sát an ninh website, malware/backdoor, hardening, backup/recovery và Incident Response theo hướng thực hành, có bước kiểm tra, bằng chứng, validation và rollback khi phù hợp.

Xem hồ sơ tác giả →