Skip to content

Hướng Dẫn Chặn Các Traffic Theo Http Referer Trên Nginx

Bài viết này sẽ hướng dẫn bạn thực hiện Chặn Các Traffic Theo Http Referer Trên Nginx. Nếu bạn cần hỗ trợ, xin vui lòng liên hệ VinaHost qua Hotline 1900 6046 ext.3, email về support@vinahost.vn hoặc chat với VinaHost qua livechat https://livechat.vinahost.vn/chat.php.

1. HTTP Referer#

Http Referer là một trường trong HTTP Header. Nó cho phép request gửi đến server là đến từ website nào (Nghĩa là người dùng không nhập URL từ trình duyệt, mà gửi request khi nhấn vào link URL từ một trang web khác).

Ví dụ khi người dùng đang ở 1 website nào đó (someone.site) và trong trang đó có đường dẫn đến website của mình (mysite.site), khi người dùng nhấn vào đường link, 1 request sẽ được gửi đến webser của ta, với trường referer là someone.site.

Điều này tạo thuận lợi khi ta muốn thống kê lưu lượng traffic, ghi log, phân loại và nhiều mục đích khác,….

Tham khảo thêm về cách tấn công sử dụng Http Referer: http://mixedbit.org/referer.html

Http Referer

2. Một số lệnh trong Nginx#

2.1. Map#

Map là 1 context trong nginx, giúp giảm bớt sự phức tạp khi sử dụng if, gần giống với switch case trong các ngôn ngữ khác.

Cú pháp của map như sau: map $bien_so_sanh $bien_ket_qua

{

Giá-trị-so-sánh-1   giá-trị-kết-quả-1;

}

Nghĩa là giá trị trong $bien_so_sanh khớp với giá trị nào trong danh sách các giá trị so sánh bên dưới thì $bien_ket_qua sẽ có giá trị tương ứng với giá-trị-kết-quả đó.

Điều này tương đương với viết nhiều dòng if kiểu:

If( $bien_so_sanh = Giá-trị-so-sánh-1) { set $bien_ket_qua  giá-trị-kết-quả-1;}

2.2. Deny, Allow#

Chặn hoặc cho phép IP, dãy IP truy cập đến webserver.

Ví dụ:

location / {
    deny  192.168.1.1;
    allow 192.168.1.0/24;
    allow 10.1.1.0/16;
    allow 2001:0db8::/32;
    deny  all;
}

2.3. valid_referers#

Được sử dụng trong server context hoặc location context. Nó chỉ ra những refer nào hợp lệ, nếu refer là hợp lệ, thì biến $invalid_referer là chuỗi rỗng, ngược lại, nó là 1.

valid_referers none blocked server_names  *.example.com example.* www.example.org/galleries/  ~\.google\.;

trong đó none là những request không có trường refer, blocked là những request bị dectected bởi firewall hay proxy, còn lại là các server name (các site cụ thể) ký tự * đại diện cho nhiều ký tự, *.example là domain kết thúc bằng example, exam* là domain có exam và kết thúc bằng bất kỳ chuỗi gì. ~ báo hiệu chuỗi sau nó là một regex và cần so sánh trường refer với regex đó (lưu ý là chuỗi domain ban đầu sau http://).

2.4. http header request trong nginx#

BiếnÝ nghĩa
$http_hostGiá trị trong trường host trong http header request.
$http_user_agentGiá trị trong trường user-agent trong http header request.
$http_refererGiá trị trong trường referer trong http header request. Full đường dẫn, ví dụ từ trang https://danit.name.vn /testproxy bấm vào link dẫn đến https://danit.name.vn thì biến có giá trị là: https://danit.name.vn/testproxy.
$http_x_forwarded_forGiá trị trường X-Forwarded-For trong header, hiển thị IP thực sự của khách hàng nếu khách hàng đứng sau 1 proxy
$http_cookieGiá trị của trường Cookie trong header, chứa dữ liệu lưu trong cookie được gửi bởi khách hàng.

3. Regex trong Nginx

3.1.So sánh chuỗi trong location context#

Trong location có các modifier hay các cách so sánh chuỗi như:

LoạiKý hiệuVí dụMatch
PrefixNone/rootCác mẫu bắt đầu bằng /root đều được chấp nhận, với nhiều case thì case nào khớp nhiều nhất sẽ được chọn
Regex~~ \.(gif|jpg|jpeg)$Các chuỗi khớp với regex đã viết.
Regex~*~* \.(gif|jpg|jpeg)$Các chuỗi khớp với regex đã viết. nhưng không phân biệt hoa thường
^~Kiểm tra theo kiểu Prefix. Và việc xử lý iên quan đến thứ tự kiểm tra của nginx

Thứ tự so sánh và lựa chọn location: Nginx sẽ so chuỗi đầu vào (uri) nào khớp với prefix dài nhất, ví dụ có 2 location là “/”“/root”, thì với uri “/root/mysite”, location “/root” sẽ được chọn do khớp nhiều hơn.

Nhưng chưa dừng lại, Nginx sẽ tiếp tục tìm kiếm các location có  regex, nó sẽ so sánh uri với các regex theo thứ tự từ trên xuống dưới trong khai báo của file config, khớp với cái nào đầu tiên nó sẽ chọn location đó.

Nếu không có nó sẽ quay lại, lấy prefix dài nhất đã chọn ban đầu.

Nhưng nếu ở location “/root” sử dụng modifier ^~ thì nó sẽ chọn luôn location này mà không kiểm tra các location regex khác nữa.

3.2. Tổng quan Regex#

Regex hay Regular Expression (biểu thức chính quy) các quy tắc để viết ra các mẫu (pattern) cho việc tìm kiếm và thay thế các chuỗi.

Ví dụ, ta có thể viết 1 regex về mẫu của địa chỉ IP (gồm 4 số cách nhau bởi dấu chấm, giá trị không quá 255). Và dùng mẫu này để kiểm tra chuỗi nhập vào có phải là IP hoặc tìm các địa chỉ IP trong file.

Các cú pháp và quy định của regex:

Ký hiệuVí dụÝ nghĩa
^^TheCác chuỗi nào bắt đầu bằng The thì match
$End$Chuỗi có từ End ở cuối câu thì match.
^ $^The End$Match với chuỗi “The End”
Khới chuỗi/end/Khớp với từ end ở bất cứ vị trí nào.
*abc*Chuỗi có từ ab, không có hoặc có 1 hay nhiều chữ c đằng sau thì match (ab,abc,abcc,…)
+abc+Chuỗi có ab, và có từ 1 đến nhiều chữ c đằng sau (abc,abcc,…)
{}abc{2}Chuỗi ab, có 2 chữ c đằng sau match: abcc
{,}Abc{2,}Chuỗi ab có từ 2 chữ c đằng sau: abcc,abccc.
()a(bc)*Chuỗi a, không có hoặc có 1 hay nhiều chuỗi bc đằng sau.
?abc?Chuỗi ab có 1 hoặc không có ký tự c đằng sau.
| []a(b|c) hay a[bc]Chuỗi a có thêm chữ b hoặc chữ c đằng sau (ab, ac,abc)
\d\dKhớp với 1 ký tự số bất kỳ: 1
\w\wKhớp với 1 ký tự chữ, số hoặc _
\s\sKhớp với ký tự khoảng trắng (và tab)
\D, \W, \SPhủ định của \d, \w, \s
[^][^a]Chuỗi không có ký tự a,
.Đại diễn cho bất kỳ ký tự nào,

Cờ (flag) trong regex:

Có một số loại cờ trong regex là g (global – tìm tất cả các chuỗi khớp với mấu, nếu không có cờ này, regex chỉ tìm chuỗi đầu tiên khớp với mẫu), cờ m (multiline chỉ rằng ^ là bắt đầu dòng, và $ là kết thúc dòng, không thì ^ là đầu chuỗi, và $ là kết thúc chuỗi.), cờ I (insensitive chỉ việc không phân biệt hoa thường, nếu chuỗi ab khớp thì chuỗi Ab cũng khớp).

Ký hiệu chỉ phạm vi: [], bên trong cặp [] là một phạm vi, mà ký tự nào khớp với 1 trong các giá trị của phạm vi thì match, ví dụ [abc], chuỗi nào có ký tự a, hoặc b, hoặc c thì match, cũng có thể viết [a-c]. Kiểm tra chuỗi có phải là chuỗi Hex: [a-fA-F0-9]*.

3.3. Một số ví dụ Regex#

Ví dụGiải thích
/[0-9]+/Tìm chuỗi có 1 hoặc nhiều ký tự số (0-9) có dấu + phía sau, nếu không có các ký tự số lượng, chỉ kiểm tra 1 ký tự duy nhất.
/^[0-9]+$/Tìm chuỗi toàn là số.
/[a-z]+/Match các chuỗi thường.
/^[a-z]+$/Match các chuỗi từ đầu đến cuối là chữ thường
/^[^a-z]/Match các chuỗi không chứa chữ thường.
/^[a-z][a-z0-9_\.]{5,32}@[a-z0-9]{2,}(\.[a-z0-9]{2,4}){1,2}$/Kiểm tra chuỗi có phải là địa chỉ email không.

Hướng dẫn về Kiểm tra chuỗi nhập vào có phải email hay không:

=> Bắt đầu bằng chữ, có 5 đến 32 ký tự (chữ cái số và dấu _) trước @, hơn 2 ký tự sau @ và một vài nhóm ký tự cách nhau bởi dấu .

-> Bắt đầu bằng chữ: ^[a-z]

-> Có 5 – đến 32 ký tự trước @: ^[a-z][a-z0-9]\_\.]{5,32}@

-> Tên miền có thể có cấp 1 hoặc cấp 2 ( .com.vn hay .com) ^[a-z][a-z0-9]\_\.]{5,32}@[a-z0-9{2,}(\.[a-z0-9]{2,4}){1,2}$/

4. Chặn lưu lượng HTTP referer trong NGINX#

4.1. Sử dụng valid_referers#

Có thể sử dụng valid_referers trong location context để ngăn chặn lưu lượng HTTP referer như sau:

location / {
         index index.php;           valid_referers none blocked danit.name.vn;           if ($invalid_referer) {                return   403;             }
}

Đọc thêm về valid_refers trong mục 2.c. Những gì liệt kê phía sau từ khóa valid_referers sẽ làm cho giá trị biến $invalid_referer là 0, giả http request gửi tới, trong header có trường referer là: https://danit.name.vn/testproxy thì phần https:// bị bỏ đi, danit.name.vn/testproxy sẽ được lấy để so với các phần trong danh sách phía sau valid_referes ở đây  danit.name.vn/testproxy khớp với danit.name.vn nên invalid_referer là 0, không bị block, nếu là một tên miền khác, thì kết quả nhận đc là 403. Valid_referers cũng có regex và ký tự đại diện *.

4.2. Dùng map, http_refer và redirect#

Có thể sử dụng map, http_refer và redirect để ngăn chặn lưu lượng HTTP referer như sau

map $http_referer $block{
    default 0;      '' 0;       https://danit.name.vn/testproxy  1; }

Tạo map context ở http context, với biến so sánh là $http_referer, biến này là biến hệ thống của nginx, chứa trường referer của http header (full đường dẫn bao gồm cả https://....). Và biến kết quả là biến block, block bằng 1 thì là block domain đó.

Ý tưởng là ta sẽ kiểm tra nếu $http_referer nằm trong danh sách bị chặn, thì biến $block sẽ có giá trị là 1, khi đó trong server context hoặc location context ta đặt lệnh sau, sẽ chặn được lưu lượng Http Referer mong muốn:

if ($block){ return 403;}

Có thể tách danh sách blacklist thành file và include vào file config chính. Lưu ý trong file hoặc cấu hình map cần có default và ‘’ chỉ rằng header không có trường referer.

Tạo file blacklist như sau:

default 0;
‘’ 0;
~testproxy$ 1;

Sau đó trong phần cấu hình map đổi thành:

map $http_referer $block{
    include blacklist;    
}

Lưu ý: reload lại nginx sau mỗi lần cập nhật

default 0;
‘’ 0; # refer rỗng thì không block
~testproxy$ 1; # Regex match với referer có đuôi là testproxy sẽ bị block.
~[0-9]$ 1; # Regex match với referer có đuôi là số sẽ bị block.
~^[0-9]; #Regex match với refer bắt đầu bằng số.
https://danit.name.vn/testproxy 1; refer giống với này sẽ bị block.

File cấu hình để ngăn chặn lưu lượng HTTP referer cuối cùng như sau:

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
events {
    worker_connections 1024;
}
http {
    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;
    map $http_referer $block{
      include referBlock.ls;
    }
    server {
        server_name  danit.name.vn wwww.danit.name.vn;
        #root         /usr/share/nginx/html;
        root /var/www/html/public_html;
        #index index.php;
        error_page 404 /404.html;
        location = /404.html {
}
       error_page 500 502 503 504 /50x.html;
        location = /50x.html {
        }
        location ~ \.php$ {
           #root           html;            #fastcgi_pass   127.0.0.1:9000;            #fastcgi_index  index.php;            #fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;             #include        fastcgi_params;
            try_files $uri =404;
            fastcgi_pass unix:/run/php-fpm/www.sock;
            fastcgi_index   index.php;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;
            include fastcgi.conf;
       }         location /testproxy {
            proxy_pass http://localhost:8000;
        }
       location / {          index index.php;          if ($block){ return 403;}         }
       listen [::]:443 ssl ipv6only=on; # managed by Certbot
       listen 443 ssl; # managed by Certbot
       ssl_certificate /etc/letsencrypt/live/danit.name.vn/fullchain.pem; # managed by Certbot
       ssl_certificate_key /etc/letsencrypt/live/danit.name.vn/privkey.pem; # managed by Certbot
       include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
       ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
   server {       if ($host = danit.name.vn) {           return 301 https://$host$request_uri;        } # managed by Certbot
       listen       80;
       listen       [::]:80;
       server_name  danit.name.vn wwww.danit.name.vn;
       return 404; # managed by Certbot
    }
}

Chúc bạn thực hiện Chặn Các Traffic Theo Http Referer Trên Nginx thành công!

THAM KHẢO CÁC DỊCH VỤ TẠI VINAHOST

>> SERVER COLOCATION – CDN

>> CLOUD – VPS

>> HOSTING

>> EMAIL

>> WEBSITE

>> TÊN MIỀN