👋 Chào mừng đến với Nocoem — kiến thức Backend, System Design và lập trình. Khám phá ngay

API Security Best Practices - Access Control

TL;DR: Kiểm soát truy cập (access control) cho API không chỉ nằm ở việc kiểm tra token hay quyền hạn trong code. Năm việc dưới đây nằm ở tầng hạ tầng, dễ bị bỏ quên, nhưng chặn được phần lớn các cuộc tấn công thô sơ trước khi chúng chạm tới logic nghiệp vụ:
  • Giới hạn tốc độ yêu cầu (rate limiting) để chống DDoS và dò mật khẩu hàng loạt (brute force).
  • Bắt buộc HTTPS với bộ mã hóa (cipher) đủ mạnh.
  • Bật tiêu đề HSTS để chặn kiểu tấn công hạ cấp kết nối (SSL strip).
  • Tắt tính năng liệt kê thư mục (directory listing) trên máy chủ web.
  • Giới hạn API nội bộ chỉ cho các địa chỉ IP tin cậy truy cập.

Bạn dựng xong API, deploy lên production, viết đủ middleware kiểm tra JWT, phân quyền theo role. Vậy là xong chưa? Chưa đâu. Trước khi một request chạm được tới logic nghiệp vụ của bạn, nó còn phải đi qua một lớp phòng thủ ở tầng hạ tầng: ai được gọi, gọi bao nhiêu lần, gọi qua kênh nào, gọi từ đâu. Lớp này thường bị bỏ qua vì nó không "vui" bằng việc viết tính năng mới, nhưng lại là thứ chặn được phần lớn các cuộc tấn công thô sơ nhất. Dưới đây là 5 điểm tôi thấy hay bị thiếu nhất khi review một API mới.

Giới Hạn Yêu Cầu

Hạn chế số lượng yêu cầu (giới hạn tốc độ) để tránh các cuộc tấn công DDoS và dò mật khẩu hàng loạt.

Giới hạn tốc độ yêu cầu (rate limiting) là điều quan trọng để ngăn chặn hai kiểu tấn công phổ biến. Tấn công từ chối dịch vụ phân tán (DDoS) làm quá tải máy chủ bằng cách dội vào một lượng request khổng lồ. Tấn công dò mật khẩu hàng loạt (brute force) thì thử đăng nhập liên tục với nhiều mật khẩu khác nhau cho tới khi trúng. Cả hai đều có một điểm chung: chúng cần gửi rất nhiều request trong thời gian ngắn. Việc giới hạn số request mà một client được gửi trong một khoảng thời gian nhất định khiến cả hai kiểu tấn công này trở nên tốn kém và chậm chạp hơn nhiều, đồng thời bảo vệ hệ thống khỏi bị quá tải.

Hãy hình dung một quầy vé chỉ có một cửa soát vé: dù bạn có 1.000 người xếp hàng, mỗi phút cửa đó cũng chỉ cho qua đúng một số lượng người nhất định. Kẻ nào cố chen ngang liên tục cũng chỉ tốn công vô ích.

Ví dụ cấu hình giới hạn 10 request/giây cho mỗi IP với Nginx:

limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;

server {
  location /api/ {
    limit_req zone=api_limit burst=20 nodelay;
    proxy_pass http://backend;
  }
}

rate=10r/s nghĩa là mỗi địa chỉ IP chỉ được 10 request/giây; burst=20 cho phép vượt ngưỡng tạm thời tối đa 20 request rồi mới bắt đầu từ chối. Với endpoint đăng nhập, bạn nên đặt ngưỡng thấp hơn nhiều (ví dụ 5 request/phút) vì đó là mục tiêu ưa thích của brute force.

Lưu ý: Giới hạn theo địa chỉ IP không phải là thuốc chữa bách bệnh. Nhiều người dùng ở cùng văn phòng có thể chung một IP công cộng (NAT) nên dễ bị chặn nhầm, còn kẻ tấn công dùng botnet thì có hàng nghìn IP khác nhau để né giới hạn. Với các endpoint nhạy cảm, nên kết hợp thêm giới hạn theo tài khoản hoặc API key, chứ đừng chỉ dựa vào IP.

Sử Dụng HTTPS

Sử dụng HTTPS ở phía máy chủ cùng các bộ mã hóa an toàn.

Đảm bảo rằng máy chủ API của bạn dùng HTTPS thay vì HTTP thuần. HTTPS mã hóa dữ liệu trong quá trình truyền, khiến việc một kẻ tấn công đánh chặn và đọc được thông tin nhạy cảm trở nên gần như bất khả thi. Để triển khai HTTPS, bạn cần có chứng chỉ SSL/TLS và cấu hình máy chủ dùng nó.

Một điểm hay bị nói lẫn: AES và ChaCha20 là bộ mã hóa đối xứng (symmetric cipher) dùng để mã hóa dữ liệu thật sự, còn ECDHE (Elliptic Curve Diffie-Hellman Ephemeral) là thuật toán trao đổi khóa, không phải cipher mã hóa dữ liệu. ECDHE được ưa chuộng vì hỗ trợ tính bí mật chuyển tiếp hoàn hảo (perfect forward secrecy): dù khóa riêng của máy chủ có bị lộ sau này, các phiên đã diễn ra trước đó vẫn không giải mã lại được. Ngược lại, các thuật toán cũ như RC4 (cipher) hay các phiên bản giao thức TLS 1.0/1.1 đã bị xem là lỗi thời, có lỗ hổng đã biết, và nên vô hiệu hóa hoàn toàn.

ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers on;

Sau khi cấu hình, bạn nên chạy thử một công cụ quét cấu hình TLS (ví dụ SSL Server Test của Qualys) để kiểm tra xem còn cipher yếu hay giao thức lỗi thời nào đang bật không.

Tiêu Đề HSTS

Dùng tiêu đề HSTS cùng SSL để tránh các cuộc tấn công hạ cấp kết nối (SSL strip).

SSL strip là kiểu tấn công mà kẻ tấn công đặt mình ở giữa (vị trí trung gian - MITM) giữa máy khách và máy chủ, đánh chặn lưu lượng, rồi âm thầm hạ cấp kết nối từ HTTPS xuống HTTP văn bản thuần (không mã hóa). Khi máy khách khởi tạo kết nối, kẻ tấn công chặn các liên kết HTTPS và thay bằng liên kết HTTP. Trình duyệt của người dùng vẫn hiển thị trang bình thường, khiến họ tưởng kết nối vẫn an toàn trong khi thực tế toàn bộ dữ liệu đang đi qua tay kẻ tấn công dưới dạng không mã hóa.

Tưởng tượng bạn quen đi vào công ty bằng cả cửa chính (khóa an toàn) lẫn cửa sau (không khóa). Kẻ gian chỉ cần dụ bạn đi cửa sau một lần là vào được. Tiêu đề HSTS giống như thông báo dán ở cổng: "từ giờ chỉ được vào bằng cửa chính, tuyệt đối không dùng cửa sau nữa" và trình duyệt sẽ tự nhớ quy tắc này.

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

max-age là số giây trình duyệt ghi nhớ quy tắc "chỉ dùng HTTPS" cho domain này (31536000 giây xấp xỉ 1 năm). includeSubDomains áp dụng luôn cho các subdomain. preload là cờ đánh dấu bạn muốn domain được đưa vào danh sách cứng trong chính trình duyệt (cần đăng ký riêng ở dịch vụ preload list), nhờ vậy ngay cả lần truy cập đầu tiên trình duyệt cũng đã biết phải dùng HTTPS chứ không đợi phản hồi header.

Danh Sách Thư Mục

Tắt tính năng liệt kê thư mục trên máy chủ web.

Liệt kê thư mục (directory listing) là tính năng của máy chủ web cho phép người dùng xem toàn bộ danh sách tệp bên trong một thư mục khi truy cập trực tiếp vào đường dẫn đó, thay vì thấy trang lỗi 403/404. Nhiều máy chủ web bật sẵn tính năng này theo mặc định. Nếu bạn để nguyên, bất kỳ ai truy cập đúng đường dẫn thư mục đều có thể thấy và tải về mọi tệp bên trong, kể cả tệp cấu hình, log, hay bản backup mà bạn quên xóa.

Nó giống như một tủ hồ sơ công ty để cửa mở toang giữa hành lang: ai đi ngang qua cũng đọc được tên khách hàng, số hợp đồng, dù không ai chủ ý cho phép điều đó.

location /uploads/ {
  autoindex off;
}
Options -Indexes

Với Nginx, autoindex mặc định đã là off, nhưng vẫn nên khai báo rõ ràng cho các thư mục chứa file tĩnh hoặc file người dùng tải lên. Với Apache, dùng chỉ thị Options -Indexes trong file cấu hình hoặc .htaccess.

Hạn Chế API Riêng Tư

API riêng tư chỉ nên được truy cập từ các địa chỉ IP nằm trong danh sách tin cậy.

Với các API nội bộ (không dành cho người dùng bên ngoài), việc chỉ cho phép truy cập từ một danh sách địa chỉ IP xác định giúp đảm bảo chỉ những hệ thống hoặc nhân viên được ủy quyền mới gọi được API đó. Bằng cách hạn chế theo IP cụ thể, bạn ngăn được phần lớn truy cập trái phép từ mạng bên ngoài, đồng thời giảm bề mặt tấn công cho các kiểu tấn công như DDoS hay brute force nhắm vào endpoint nội bộ.

location /internal-api/ {
  allow 203.0.113.10;
  allow 203.0.113.0/24;
  deny all;
}

Cấu hình trên chỉ cho phép một IP cụ thể và một dải mạng nội bộ truy cập vào /internal-api/, còn lại đều bị từ chối.

Lưu ý: Danh sách IP tin cậy giống một danh sách khách mời ở cổng nhưng bảo vệ chỉ kiểm tra biển số xe: nếu máy chủ cloud của bạn đổi IP, hoặc bạn quên gỡ IP của nhân viên cũ, danh sách sẽ nhanh chóng lỗi thời. Địa chỉ IP nguồn cũng có thể bị giả mạo ở một số kịch bản mạng, nên với dữ liệu thật sự nhạy cảm, hãy kết hợp thêm xác thực lẫn nhau bằng chứng chỉ (mTLS) hoặc đặt API sau một VPN riêng, thay vì chỉ dựa vào IP allowlist.

Tóm Tắt

  • Giới hạn tốc độ yêu cầu chặn DDoS và brute force, nhưng nên kết hợp giới hạn theo tài khoản/API key chứ không chỉ theo IP.
  • Luôn bắt buộc HTTPS, chọn đúng cipher mã hóa (AES, ChaCha20) và thuật toán trao đổi khóa (ECDHE), tắt hẳn TLS 1.0/1.1 và cipher yếu như RC4.
  • Bật tiêu đề HSTS để trình duyệt tự động từ chối kết nối HTTP, chặn kiểu tấn công SSL strip.
  • Tắt liệt kê thư mục để tránh lộ danh sách file nhạy cảm trên máy chủ.
  • Giới hạn API nội bộ theo IP tin cậy, nhưng đừng xem đó là lớp bảo vệ duy nhất cho dữ liệu nhạy cảm.

- Kai

Thấy bài viết hữu ích?

0 lượt thích

Đăng nhận xét