Chuyển đến nội dung chính (Skip to content)
Mục lục bài viết
Nginx

Bảo mật NGINX: headers và giới hạn truy cập

Bảo mật NGINX: headers và giới hạn truy cập

Ẩn phiên bản, đánh giá security headers và triển khai rate limiting theo endpoint. Giải thích giới hạn của chặn bot, CSP và bảo vệ theo IP.

Trước khi bắt đầu. Cấu hình bảo mật phải theo ngữ cảnh ứng dụng. Đặt giới hạn quá thấp hoặc sao chép CSP chưa kiểm tra có thể chặn người dùng hợp lệ và làm lỗi đăng nhập, thanh toán hoặc tài nguyên bên ngoài.

Sơ đồ kiểm tra bảo mật nginx
Hai nhánh kiểm tra ban đầu: trình duyệt / tài nguyên hoặc lưu lượng / endpoint. Chạm vào hình để mở bản lớn.

1. Nguyên tắc bảo mật chuyên sâu (Defense in Depth) trên NGINX

Trong quy trình rà quét lỗ hổng của kẻ tấn công, bước đầu tiên luôn là Reconnaissance (Thu thập thông tin mục tiêu). Bằng cách đọc response header Server (ví dụ: Server: nginx/1.18.0 (Ubuntu)), kẻ tấn công có thể xác định chính xác số hiệu phiên bản và phân phối hệ điều hành đang sử dụng, từ đó tra cứu các mã khai thác (Exploit/CVE) tương ứng.

Một hệ thống NGINX chuẩn Production cần áp dụng chiến lược phòng thủ nhiều lớp (Defense in Depth): ẩn định danh máy chủ, siết chặt chính sách trình duyệt thông qua các Security Headers, giới hạn tần suất gửi request để ngăn chặn brute-force và loại trừ nguy cơ rò rỉ dữ liệu từ các file cấu hình nhạy cảm.

Minh họa Request từ client → Headers và giới hạn → Ứng dụng backend
Luồng khái niệm: Request từ client → Headers và giới hạn → Ứng dụng backend. Chạm vào hình để mở bản lớn.

2. Ẩn thông tin phiên bản với server_tokens và headers-more

Cách 1: Sử dụng directive gốc server_tokens off; (Khuyên dùng)

Đây là giải pháp đơn giản, hiệu quả và được tích hợp sẵn trong mọi bản phân phối NGINX mà không cần biên dịch lại mã nguồn hay cài đặt thêm module bên ngoài.

Mở file /etc/nginx/nginx.conf và thêm vào khối http:

http {
    # Ẩn hoàn toàn số hiệu phiên bản NGINX trong response header và trang báo lỗi
    server_tokens off;
    ...
}

Sau khi thiết lập, header Server sẽ chỉ trả về chuỗi Server: nginx mà không còn hiển thị số phiên bản cụ thể (ví dụ 1.25.4) hay tên hệ điều hành (Ubuntu/Debian).

Cách 2: Xóa hoàn toàn header Server bằng module headers-more-nginx-module

Nếu chính sách an ninh của doanh nghiệp yêu cầu xóa sạch hoàn toàn chuỗi Server trong mọi phản hồi HTTP, bạn có thể cài đặt module động headers-more:

# Trên Ubuntu / Debian:
sudo apt install -y libnginx-mod-http-headers-more-filter

Khai báo trong khối http hoặc từng khối server:

http {
    # Xóa hoàn toàn header Server khỏi phản hồi HTTP
    more_clear_headers Server;
}

3. Đánh giá và triển khai security headers

Các Security Headers hướng dẫn trình duyệt người dùng áp dụng các biện pháp bảo vệ tích hợp sẵn, ngăn chặn các hình thức tấn công phổ biến như Cross-Site Scripting (XSS), Clickjacking và MIME Sniffing.

Tạo file /etc/nginx/snippets/security-headers.conf:

# 1. Chống Clickjacking: Không cho phép nhúng website vào iframe từ domain khác
add_header X-Frame-Options "SAMEORIGIN" always;

# 2. Chống MIME-type Sniffing: Bắt buộc trình duyệt tuân thủ MIME type từ server
add_header X-Content-Type-Options "nosniff" always;

# 3. Quản lý thông tin nguồn giới thiệu (Referrer Policy)
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

# 4. Giới hạn quyền truy cập thiết bị phần cứng của trình duyệt (Camera, Micro, Vị trí)
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()" always;

# 5. CSP Report-Only: chi quan sat; can dieu chinh theo ung dung truoc enforce
add_header Content-Security-Policy-Report-Only "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline' https:; img-src 'self' data: https:; font-src 'self' data: https:; connect-src 'self' https:; frame-ancestors 'self';" always;

# 6. Ngăn chặn rò rỉ dữ liệu chéo nguồn (Cross-Origin isolation)
add_header Cross-Origin-Opener-Policy "same-origin" always;
add_header Cross-Origin-Resource-Policy "same-origin" always;

4. Thiết lập rate limiting chống Brute-force và DDoS lớp ứng dụng

Rate Limiting (Giới hạn tần suất request) là cơ chế hữu ích của NGINX để bảo vệ các cổng API đăng nhập hoặc các endpoint nặng khỏi bị spam request gây kiệt quệ tài nguyên CPU/RAM.

NGINX sử dụng thuật toán Leaky Bucket để điều tiết lưu lượng mượt mà:

Bước 4.1: Khai báo vùng nhớ chia sẻ trong khối http của /etc/nginx/nginx.conf

http {
    # Vùng nhớ lưu trữ địa chỉ IP (10MB lưu được khoảng 160.000 địa chỉ IP)
    # Giới hạn mỗi IP tối đa 10 request/giây cho toàn site
    limit_req_zone $binary_remote_addr zone=general_limit:10m rate=10r/s;
    
    # Giới hạn khắt khe hơn cho trang đăng nhập/API: tối đa 2 request/giây
    limit_req_zone $binary_remote_addr zone=login_limit:10m rate=2r/s;

    # Giới hạn số lượng kết nối đồng thời từ một địa chỉ IP duy nhất
    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
    
    # Thiết lập mã lỗi trả về khi bị chặn (HTTP 429 Too Many Requests)
    limit_req_status 429;
    limit_conn_status 429;
}

Bước 4.2: Áp dụng vào từng server block hoặc Location cụ thể

server {
    listen 443 ssl;
    server_name example.com;
    
    # Giới hạn tối đa 20 kết nối đồng thời từ một IP
    limit_conn conn_limit 20;

    # Áp dụng giới hạn chung cho toàn bộ website với bộ đệm burst=20
    location / {
        limit_req zone=general_limit burst=20 nodelay;
        try_files $uri $uri/ =404;
    }

    # Bảo vệ nghiêm ngặt endpoint đăng nhập hoặc API nhạy cảm
    location /api/login {
        limit_req zone=login_limit burst=5 nodelay;
        proxy_pass http://backend_upstream;
    }
}

5. Chặn truy cập vào các file ẩn và tài nguyên nhạy cảm

Rất nhiều sự cố rò rỉ dữ liệu xảy ra do quản trị viên vô tình đẩy file chứa biến môi trường (.env) hoặc thư mục quản lý phiên bản (.git) lên thư mục web root công khai.

Thêm đoạn chặn triệt để sau vào các Server Block:

# 1. Chặn toàn bộ file và thư mục ẩn bắt đầu bằng dấu chấm (trừ /.well-known dùng cho SSL Certbot)
location ~ /\.(?!well-known) {
    deny all;
    access_log off;
    log_not_found off;
    return 404;
}

# 2. Chặn các file sao lưu, cấu hình và dump cơ sở dữ liệu phổ biến
location ~* \.(bak|config|sql|fla|psd|ini|log|sh|inc|swp|dist|env)$ {
    deny all;
    access_log off;
    log_not_found off;
    return 404;
}

6. Chặn tự động các bot và web scraper độc hại

Để ngăn chặn các công cụ quét tự động tiêu tốn băng thông và dò quét điểm yếu, bạn có thể tạo một danh sách lọc dựa trên chuỗi User-Agent:

# Khai báo trong khối http
map $http_user_agent $bad_bot {
    default 0;
    ~*(nikto|sqlmap|acunetix|w3af|netsparker|dirbuster|pangolin|nmap) 1;
    # Khong chan bot tim kiem theo danh sach mau neu chua co chinh sach.
}

# Khai báo trong khối server
server {
    if ($bad_bot) {
        return 403 "Access denied by local policy.";
    }
}

7. File cấu hình bảo mật tổng hợp dùng chung

Sau khi thiết lập hoàn tất, bạn chỉ cần include file security-headers.conf vào mọi Virtual Host trên hệ thống. Kiểm tra cú pháp và reload dịch vụ:

sudo nginx -t && sudo systemctl reload nginx

Kiểm tra phản hồi thực tế bằng curl:

curl -I https://example.com

Bạn sẽ thấy phản hồi trả về đầy đủ các header an toàn, không còn số hiệu phiên bản máy chủ và hệ thống đã được gia cố vững chắc trước các cuộc tấn công thăm dò.

Ở bài học tiếp theo, chúng ta sẽ tối ưu hóa tốc độ truyền tải tài nguyên lên mức tối đa bằng việc kích hoạt giao thức HTTP/2 và thế hệ mới HTTP/3 (QUIC).

server_tokens off ẩn số phiên bản, không vá lỗ hổng và không xóa tên sản phẩm khỏi mọi phản hồi. Module headers-more phải khớp ABI và nguồn gói NGINX; không trộn module của gói hệ điều hành với binary từ kho khác khi chưa xác minh. Với CSP Report-Only, kiểm tra console và báo cáo rồi mới cân nhắc enforce. Chặn theo User-Agent chỉ là một tín hiệu dễ giả mạo. Khi ở sau CDN/proxy, xác minh nguồn IP đáng tin cậy trước khi rate limit; dùng dry-run và theo dõi 429 để tránh chặn cả văn phòng dùng chung NAT. Rate limit tại web server không thay thế chống DDoS ở lớp mạng.

Nguồn đối chiếu và kiểm tra trước khi áp dụng

Các địa chỉ example.com, IP riêng và đường dẫn trong ví dụ cần thay theo môi trường thực tế. Các sơ đồ trong bài là minh họa khái niệm, không phải bằng chứng thử nghiệm trên hệ thống của bạn.

Trước khi áp dụng: sao lưu file cấu hình bị đổi, chạy sudo nginx -t, chỉ reload khi kiểm tra thành công, rồi xác nhận endpoint, error log và chức năng ứng dụng. Nếu lỗi xuất hiện, phục hồi file đã sao lưu, kiểm tra cú pháp và reload lại; không xóa hàng loạt cấu hình để thử.

Tìm hiểu thêm

Xem toàn bộ lộ trình Nginx