Hướng dẫn đầy đủ về cách triển khai Netfilter và Suricata trên Linux

Cập nhật lần cuối: 1 tháng 2026
  • NFQUEUE cho phép Netfilter ủy quyền các quyết định lọc và đánh dấu cho các tiến trình trong không gian người dùng, từ đó tạo điều kiện cho các tường lửa và bộ định tuyến IP động.
  • Suricata cung cấp một công cụ IDS/IPS đa tiến trình với hỗ trợ NFQUEUE, AF_PACKET và các quy tắc tương thích với Snort và Emerging Threats.
  • Việc tích hợp NFQUEUE với Suricata, cơ sở dữ liệu, Memcached hoặc Pfsense cho phép bạn xây dựng các giải pháp định tuyến và bảo mật tiên tiến bằng phần mềm miễn phí.
  • Hiệu năng phụ thuộc phần lớn vào thiết kế luồng và logic trong không gian người dùng, do đó việc tối ưu hóa và lựa chọn cẩn thận lưu lượng truy cập cần kiểm tra là rất quan trọng.

Triển khai Netfilter và Suricata

Nếu bạn làm việc với mạng trên GNU/Linux ( một trong những bản phân phối Linux tốt nhất về bảo mật và quyền riêng tư ) và muốn vượt ra ngoài tường lửa tĩnh thông thường, có lẽ bạn đang tò mò về cách kết hợp Netfilter, NFQUEUE và Suricata để xây dựng một hệ thống IDS/IPS thực sự linh hoạt mà không cần tốn quá nhiều tiền cho phần cứng độc quyền. Đó chính là lĩnh vực chúng ta sẽ khám phá trong bài viết này, kết hợp các yếu tố cấp thấp (kernel, hàng đợi, C) với các công cụ cấp cao (Suricata, quy tắc, MySQL, Memcached, pfSense).

Ý tưởng cốt lõi rất mạnh mẽ: tận dụng thực tế rằng nhân hệ điều hành (xem cách tối ưu hóa nhân Linux ) có thể xếp hàng các gói tin vào không gian người dùng và cho phép một chương trình tùy chỉnh quyết định phải làm gì với chúng. Điều này có thể được sử dụng để lọc lưu lượng (tường lửa nâng cao, IPS), định tuyến động hoặc tích hợp logic nghiệp vụ (cơ sở dữ liệu, bộ nhớ đệm, phát hiện tấn công ứng dụng web, VoIP, v.v.). Và nếu chúng ta thêm Suricata như một công cụ IDS/IPS đa tiến trình, chúng ta sẽ có một sự kết hợp rất mạnh mẽ cho các môi trường từ phòng thí nghiệm đến các trung tâm dữ liệu có lưu lượng truy cập cao.

NFQUEUE và Netfilter: nâng cấp tường lửa lên không gian người dùng

Trong một hệ thống GNU/Linux điển hình, các quy tắc Netfilter/iptables (hoặc nftables) thường được sử dụng như các chính sách tĩnh nằm hoàn toàn trong không gian kernel . Các thiết bị đầu cuối và thiết bị chuyên dụng (bao gồm nhiều giải pháp dựa trên Netfilter hoặc Packet Filter của BSD) lưu trữ cấu hình trong các tệp văn bản, XML hoặc SQLite, và khi có thay đổi, chúng sẽ tạo lại và tải lại các quy tắc. Điều này khá linh hoạt, nhưng logic vẫn là một dạng ảnh chụp nhanh của tường lửa với các tinh chỉnh động nhỏ (giới hạn kết nối mỗi giây, conntrack, khớp quốc gia, lớp 7 nếu có, v.v.).

Những gì NFQUEUE đề xuất là một bước đột phá: thay vì nhân hệ điều hành luôn đưa ra quyết định cuối cùng, chúng ta có thể ủy thác quyết định đó cho một tiến trình người dùng . Nhân hệ điều hành sẽ xếp gói tin vào một hàng đợi được đánh số, và một ứng dụng sử dụng thư viện libnetfilter_queue sẽ truy xuất gói tin, phân tích nó và trả về phán quyết: chấp nhận, loại bỏ, hoặc thậm chí đánh dấu nó để định tuyến theo chính sách. Nó giống như việc có một "thẩm phán" có thể lập trình được viết bằng C, Python hoặc Perl trên đỉnh tường lửa.

Điều tuyệt vời ở đây là chương trình của chúng ta có thể làm bất cứ điều gì mình muốn: truy vấn /dev/urandom, cơ sở dữ liệu, dịch vụ web, bộ nhớ đệm phân tán hoặc thuật toán phức tạp trước khi phản hồi lại nhân hệ điều hành. Về mặt kiến ​​trúc, tường lửa không còn là một tập hợp các quy tắc tĩnh đơn giản mà trở thành một đường ống nơi Netfilter, hàng đợi và các ứng dụng người dùng kết hợp với nhau như những mảnh ghép của một bức tranh.

NFQUEUE bao gồm hai phần: mục tiêu NFQUEUE trong iptables , có chức năng gửi các gói tin đến một hàng đợi cụ thể, và thư viện người dùng libnetfilter_queue , cho phép bạn đọc các gói tin đó và đưa ra phán quyết. Nó không phải là một công cụ bắt gói tin đơn giản như tcpdump: ở đây chúng ta có khả năng trực tiếp quyết định đường đi của gói tin.

công cụ giám sát hệ thống nâng cao dành cho Linux
Bài viết liên quan:
Hướng dẫn đầy đủ về Trình giám sát hệ thống nâng cao dành cho Linux:

Cấu hình iptables cơ bản với NFQUEUE

Từ góc độ iptables, việc sử dụng NFQUEUE khá đơn giản: bạn thêm một quy tắc vào chuỗi mà bạn quan tâm để gửi vào hàng đợi các gói tin đáp ứng các tiêu chí nhất định (địa chỉ IP nguồn/đích, cổng, trạng thái, các mô-đun bổ sung như GeoIP hoặc layer7 nếu có, v.v.).

Ví dụ, nếu chúng ta muốn gửi tất cả các gói ping đến chính máy chủ đó vào NFQUEUE:

iptables -I INPUT -p icmp -j NFQUEUE

Lệnh này gửi các gói ICMP đến hàng đợi 0 (trừ khi có chỉ định khác). Chúng ta có thể chỉ định một hàng đợi khác bằng lệnh như `--queue-num 3` . Khi liệt kê các quy tắc với bộ đếm (`iptables -L -n -v -x`), chúng ta sẽ thấy các bộ đếm tăng lên, cho thấy các gói đang được xếp vào hàng đợi . Một chi tiết quan trọng: nếu có các gói trong hàng đợi và không có tiến trình người dùng nào truy xuất và xử lý chúng, hành vi mặc định là từ chối chúng, vì vậy, theo thiết kế, lỗi ứng dụng sẽ dẫn đến việc lưu lượng truy cập bị chặn.

Lập trình với thư viện libnetfilter_queue: chương trình "hello world" bằng ngôn ngữ C.

Để tham gia hàng đợi từ không gian người dùng, thư viện libnetfilter_queue được sử dụng (thư viện này lại phụ thuộc vào libnfnetlink). Trên các bản phân phối như Debian, chỉ cần cài đặt các gói phát triển:

apt-get install libnfnetlink-dev libnetfilter-queue-dev gcc

Cấu trúc cơ bản của một chương trình tối thiểu luôn chấp nhận gói tin bao gồm một vài bước rất rõ ràng: mở thư viện, hủy liên kết bất kỳ trình xử lý hiện có nào, liên kết với giao thức AF_INET, tạo hàng đợi với một hàm gọi lại, xác định chế độ sao chép và vào vòng lặp nhận . Hàm gọi lại được thực thi cho mỗi gói tin trong hàng đợi, trích xuất ID và trả về kết quả.

Trên thực tế, quy trình diễn ra như sau: `nfq_open` để lấy handle, `nfq_unbind_pf` để dọn dẹp, `nfq_bind_pf` để liên kết với AF_INET, `nfq_create_queue` để đăng ký hàm gọi lại trong hàng đợi 0, `nfq_set_mode` để chỉ định xem chúng ta muốn siêu dữ liệu hay toàn bộ gói tin, một vòng lặp với `recv()` trên mô tả, và `nfq_handle_packet` để xử lý từng gói tin . Khi kết thúc, hàng đợi được hủy bằng `nfq_destroy_queue` và handle được đóng bằng `nfq_close`.

Loại "hello world" này cho phép đo lường chính xác tác động của NFQUEUE. Nếu ta biên dịch ví dụ với một cái gì đó như sau:

gcc -o nftest code.c -lnfnetlink -lnetfilter_queue

Và nếu chúng ta xếp hàng lưu lượng truy cập từ iperf (ví dụ: cổng TCP 5001 trong INPUT và OUTPUT), chúng ta sẽ thấy rằng đoạn mã chỉ đơn giản là chấp nhận các gói tin hầu như không ảnh hưởng đến hiệu suất trên mạng gigabit . Tuy nhiên, có một chi tiết quan trọng: việc in thông tin trong hàm gọi lại (printf, fflush, v.v.) làm giảm đáng kể thông lượng, như có thể thấy khi so sánh iperf có và không có gỡ lỗi màn hình.

Các tùy chọn NFQUEUE nâng cao: bỏ qua, cân bằng và mở khi gặp sự cố.

NFQUEUE tích hợp một số tùy chọn iptables thú vị giúp thay đổi hành vi mặc định của hàng đợi và cần được biết trước khi triển khai trong môi trường sản xuất hoặc hiệu năng cao, vì chúng ảnh hưởng đến cách xử lý lỗi ứng dụng người dùng hoặc tình trạng đầy hàng đợi.

Lệnh `--queue-bypass` cho phép bạn đảm bảo rằng nếu không có tiến trình nào đang lắng nghe hàng đợi, các gói tin sẽ không bị loại bỏ mà thay vào đó được chuyển tiếp đến bước tiếp theo trong chuỗi iptables. Điều này có thể hữu ích nếu bạn muốn hệ thống "hoạt động mở" khi dịch vụ người dùng không khả dụng, mặc dù từ góc độ bảo mật, đây là con dao hai lưỡi.

Tùy chọn `--queue-balance` cho phép bạn phân phối các gói tin trên một phạm vi hàng đợi (ví dụ: từ 0 đến 3) và sau đó có nhiều tiến trình hoặc luồng độc lập tiêu thụ từ mỗi hàng đợi . Mã của Netfilter đảm bảo rằng các gói tin từ cùng một luồng luôn được đưa vào cùng một hàng đợi, điều này giúp đơn giản hóa đáng kể việc duy trì tính nhất quán trong logic quyết định.

Ngoài ra còn có chế độ `--fail-open` , chế độ này kiểm soát những gì xảy ra khi hàng đợi đầy do tiến trình người dùng chạy quá chậm. Kích hoạt chế độ này khiến nhân hệ điều hành chấp nhận các gói tin trực tiếp thay vì loại bỏ chúng, ngăn chặn sự gián đoạn lưu lượng truy cập lớn. Tuy nhiên, điều này cũng có thể là một vấn đề bảo mật, bởi vì nếu chúng ta muốn đưa ra quyết định dựa trên từng trường hợp cụ thể, việc mất các gói tin quyết định đồng nghĩa với việc không đạt được mục tiêu đó.

Để theo dõi những gì đang xảy ra với các hàng đợi, Netfilter hiển thị thông tin trong pseudo-fs /proc/net/netfilter/nfnetlink_queue , thông tin này có thể dễ dàng được truy vấn từ các tập lệnh hoặc công cụ giám sát.

Tích hợp logic nghiệp vụ: kiểm thử với Memcached và MySQL

Khi quy trình "hello world" đã được kiểm soát, bước tiếp theo tự nhiên là làm phong phú thêm hàm gọi lại bằng các cuộc gọi đến các hệ thống bên ngoài . Một thí nghiệm điển hình bao gồm việc quyết định chấp nhận hay từ chối một gói tin dựa trên việc địa chỉ IP nguồn có xuất hiện trong bất kỳ hệ thống phụ trợ nào hay không, chẳng hạn như cơ sở dữ liệu MySQL hoặc bộ nhớ đệm Memcached.

  Deepfakes: phân tích, tác động thực tế và những thách thức chính

Trong trường hợp của Memcached, daemon được cài đặt (apt-get install memcached) và một khóa, ví dụ như authorized , được tải với địa chỉ IP mà chúng ta quan tâm. Chúng ta có thể thực hiện điều này bằng lệnh echo và netcat đơn giản, sau đó xác minh bằng lệnh get rằng giá trị đã được lưu trữ chính xác. Từ đó, chương trình NFQUEUE, ngoài việc lấy ID gói tin, còn nhận toàn bộ gói tin bằng NFQNL_COPY_PACKET , trích xuất tiêu đề IP (struct iphdr), và chuyển đổi địa chỉ nguồn thành chuỗi bằng inet_ntop.

Để tránh lãng phí thời gian mở kết nối với mỗi gói tin, kết nối Memcached chỉ được khởi tạo một lần trong phương thức chính (memcached_create, memcached_server_list_append, memcached_server_push), và trình xử lý được lưu trữ trong các biến toàn cục. Trong hàm callback, hàm memcached_get được gọi với khóa mong muốn, địa chỉ IP nguồn được so sánh với giá trị nhận được, và nếu chúng khớp, hàm trả về NF_ACCEPT; ngược lại, hàm trả về NF_DROP. Nếu khóa không tồn tại hoặc có lỗi, gói tin sẽ bị loại bỏ như một chính sách thận trọng.

Sử dụng iperf, chiến lược này làm giảm thông lượng xuống khoảng 140 Mbit/s trên mạng gigabit , và người ta nhận thấy hàng đợi bắt đầu bị mất dữ liệu (được chỉ ra, ví dụ, bằng các ký hiệu trong chính mã lệnh). Nói cách khác, chỉ riêng việc gọi một dịch vụ bộ nhớ đệm cho mỗi gói tin đã gây ra chi phí đáng kể, mặc dù nó vẫn khả thi đối với lưu lượng truy cập trung bình nếu được tối ưu hóa.

Với MySQL, cách tiếp cận tương tự nhưng phức tạp hơn: thư viện máy chủ và máy khách được cài đặt, một cơ sở dữ liệu (ví dụ: nfqueue) được tạo với một bảng đơn giản có tên là authorized(ip varchar(50)), và địa chỉ IP được cho phép được chèn vào. Trong chương trình, `mysql_init` và `mysql_real_connect` được chạy khi khởi động, và trong hàm gọi lại, một truy vấn như `select * from authorized where ip like 'xxxx'` được xây dựng. Nếu truy vấn thực thi thành công và tìm thấy một hàng, gói tin được chấp nhận; ngược lại, nó bị loại bỏ.

Khi bật bộ nhớ đệm truy vấn MySQL, các thử nghiệm cho kết quả khoảng 188 Mbit/s , giảm xuống còn 103 Mbit/s khi tắt bộ nhớ đệm truy vấn. Những con số này, dù còn xa tốc độ gigabit, cho thấy ngay cả với phương pháp kém hiệu quả nhất (đơn luồng, không tối ưu hóa) , vẫn có thể xử lý được lưu lượng truy cập đáng kể bằng các quyết định dựa trên cơ sở dữ liệu hoặc dựa trên bộ nhớ đệm.

Hiệu năng, đa luồng và mức sử dụng CPU

Các bài kiểm tra với iperf, Memcached và MySQL cho thấy rõ ràng rằng giới hạn hiệu năng không phải do chính NFQUEUE đặt ra mà là do logic chúng ta thêm vào trong không gian người dùng và cách chúng ta triển khai nó. Một chương trình thực thi chỉ trả về NF_ACCEPT đạt được gần một gigabit mà không gặp khó khăn; ngay khi chúng ta đưa vào các thao tác I/O hoặc các lệnh gọi mạng, thông lượng sẽ giảm và CPU của máy NFQUEUE, daemon Memcached hoặc MySQL bị đẩy đến giới hạn của nó.

Từ góc độ kiến ​​trúc, điều này có hai hàm ý. Một mặt, nó khẳng định rằng việc ủy ​​quyền các quyết định tường lửa cho các ứng dụng người dùng đối với lưu lượng truy cập lớn là hoàn toàn khả thi , miễn là tính đến chi phí thực tế của mỗi lần gọi. Mặt khác, nó chứng minh rằng để tiếp cận khả năng tối đa của nền tảng , cần phải xem xét đa luồng hoặc đa xử lý . NFQUEUE cho phép phân phối lưu lượng truy cập trên nhiều hàng đợi; chúng ta có thể khởi chạy nhiều bản sao của ứng dụng, mỗi bản sao lắng nghe một hàng đợi khác nhau và tận dụng nhiều lõi mà không cần phải sử dụng pthreads hoặc các tiến trình con phức tạp.

Một tối ưu hóa rõ ràng khác là giới hạn lưu lượng truy cập đi qua NFQUEUE . Trong các thử nghiệm, toàn bộ luồng iperf đều được xếp vào hàng đợi, nhưng trong kịch bản thực tế, chúng ta có thể chỉ xếp vào hàng đợi các gói có trạng thái NEW, cho phép các gói ESTABLISHED/RELATED đi qua và dành logic tốn kém cho việc đăng nhập hoặc các mẫu đáng ngờ.

Tóm lại, việc sử dụng CPU và thiết kế luồng là yếu tố then chốt: nếu tiến trình người dùng không đáp ứng được yêu cầu, hàng đợi sẽ đầy và chúng ta phải dùng đến các biện pháp như mở lại khi gặp lỗi hoặc chấp nhận bỏ qua yêu cầu, làm mất đi một số khả năng kiểm soát chính xác mà phương pháp này hướng tới.

Định tuyến động với thương hiệu Netfilter

NFQUEUE không chỉ giới hạn ở việc nói "chấp nhận" hoặc "loại bỏ". Nó cũng có thể được sử dụng để áp dụng các cờ Netfilter (fwmark) cho các gói tin và kết hợp chúng với ip rule và iproute2 để tạo ra các sơ đồ định tuyến chính trị kiểu VRF rất linh hoạt, gần như nhẹ.

Nhìn chung, quy trình sẽ như sau: định nghĩa một vài bảng định tuyến trong /etc/iproute2/rt_tables , ví dụ như slow và fast; gán cho mỗi bảng một tuyến đường mặc định khác nhau (một tuyến qua cáp quang và một tuyến qua liên kết hạn chế hơn); sử dụng quy tắc ip để chỉ định rằng các gói có fwmark 1 sẽ được chuyển đến bảng fast, các gói có fwmark 2 đến bảng slow, v.v.; và cuối cùng, sử dụng NFQUEUE để đánh dấu các gói một cách thích hợp trước khi trả về kết quả.

Để thiết lập phán quyết từ hàm gọi lại, ta sử dụng `nfq_set_verdict2` , tương tự như `nfq_set_verdict` nhưng cho phép bạn thiết lập giá trị phán quyết mà `ip rule` sẽ thấy. Kết hợp tất cả những điều này, bạn có thể xây dựng một bộ định tuyến IP quyết định định tuyến dựa trên các tiêu chí tùy ý: từ những điều phi lý như kích thước gói tin chẵn/lẻ đến các đầu vào bên ngoài như thuật toán dự đoán lưu lượng, sự kiện trên mạng xã hội hoặc tín hiệu từ hệ thống giám sát.

Kết quả là một hệ thống trong đó nhân hệ điều hành tiếp tục chuyển tiếp các gói dữ liệu với tốc độ thông thường, nhưng đường đi chính xác của mỗi luồng dữ liệu được giao cho phần mềm bên ngoài , phần mềm này có thể thay đổi quyết định của mình trong thời gian thực mà không cần can thiệp vào các quy tắc tĩnh.

NFQUEUE và Suricata: Hệ thống ngăn chặn xâm nhập cấp cao trong GNU/Linux

Tất cả những điều trên đều có thể được lập trình thủ công bằng ngôn ngữ C, nhưng khi nói đến phát hiện xâm nhập và kiểm tra gói dữ liệu chuyên sâu, lựa chọn hợp lý thường là dựa vào một hệ thống IDS/IPS hoàn thiện . Đó là lý do Suricata ra đời, được tạo ra chính xác như một giải pháp thay thế đa tiến trình cho Snort, với khả năng IPS ngay từ đầu và tập trung mạnh vào việc tận dụng nhiều lõi CPU hiện có.

Suricata được viết lại từ đầu và phân phối theo giấy phép GPLv2 ; Tổ chức An ninh Thông tin Mở (OISF) duy trì cả công cụ và một hệ sinh thái khá toàn diện gồm các quy tắc và tài liệu. Không giống như Snort 2.x, vốn kế thừa một lõi đơn luồng và được vá lỗi thêm vào đó, Suricata được thiết kế để phân chia khối lượng công việc trên nhiều luồng: thu thập, giải mã, phát hiện và xuất, với các chiến lược chia sẻ tải khác nhau.

Về mặt chức năng, Suricata cung cấp hỗ trợ gốc cho IPv6, kiểm tra lớp 7 (HTTP rất tiên tiến thông qua thư viện HTP), nhận dạng giao thức độc lập với cổng , tái tạo luồng và một hệ thống biến phiên (flowbits) rất mạnh mẽ để tương quan các giai đoạn khác nhau của một cuộc tấn công trải rộng trên nhiều kết nối TCP.

Một điểm mạnh khác là khả năng tương thích với các quy tắc Snort và khả năng sử dụng cả bộ chữ ký Sourcefire VRT và Emerging Threats (phiên bản miễn phí ET Open và phiên bản thương mại ET Pro). Hơn nữa, nó xuất các sự kiện ở các định dạng rất hữu ích (fast.log, JSON trong eve.json) để tích hợp với SIEM, ELK, Splunk và các hệ thống khác.

Suricata như một IPS trong Linux: các chế độ bắt gói và NFQUEUE

Trên GNU/Linux, Suricata có thể hoạt động ở các chế độ khác nhau tùy thuộc vào cách thức chặn lưu lượng truy cập: NFQUEUE, AF_PACKET, PF_RING, libpcap, NFLOG, IPFW, DAG, Napatech … Mỗi chế độ đều có ưu điểm và yêu cầu riêng. Ở cấp độ IPS thuần túy, hai chế độ quan trọng nhất là NFQUEUE và AF_PACKET.

Ở chế độ NFQ (NFQUEUE) , luồng hoạt động tương tự như đã mô tả trước đó: một tập hợp các quy tắc iptables gửi các gói tin đến một hàng đợi; Suricata, chạy trong không gian người dùng, đọc từ hàng đợi đó, kiểm tra nội dung theo các quy tắc của nó và trả về phán quyết cho nhân hệ điều hành: NF_ACCEPT, NF_DROP hoặc NF_REPEAT. Lựa chọn thứ ba có thể được sử dụng để đưa lại gói tin vào cùng bảng iptables sau khi áp dụng các dấu hiệu hoặc sửa đổi bổ sung.

Chế độ này rất linh hoạt và dễ triển khai trong các cơ sở hạ tầng hiện có , vì nó chỉ yêu cầu sửa đổi các quy tắc tại các điểm cụ thể (ví dụ: FORWARD, INPUT, OUTPUT) và giữ nguyên mọi thứ khác. Chi phí phát sinh là việc truyền tải các gói tin lên xuống thông qua NFQUEUE, với tác động đã đề cập ở trên nếu khối lượng dữ liệu rất lớn hoặc các quy tắc tốn nhiều tài nguyên.

Ở chế độ AF_PACKET , Suricata hoạt động gần hơn với giao diện mạng, sao chép các gói tin qua các socket AF_PACKET. Đây là phương pháp không sao chép nhanh hơn nhiều , nhưng nó yêu cầu hệ thống phải hoạt động như một cổng với hai giao diện và việc chặn lưu lượng phải được thực hiện ở cấp độ chuyển tiếp giữa các NIC: gói tin cần chặn đơn giản là không được truyền từ giao diện đầu vào đến giao diện đầu ra.

  Các chương trình diệt virus nguy hiểm: những chương trình nào nên tránh và cách bảo vệ máy tính của bạn

Ở cả hai chế độ, Suricata đều có thể được kết hợp với Netfilter, nhưng NFQUEUE đặc biệt phù hợp trong các trường hợp chúng ta muốn tái sử dụng toàn bộ logic của iptables (chính sách, phạm vi, quy tắc trước đó) và chỉ gửi đến Suricata lưu lượng truy cập mà chúng ta muốn kiểm tra chuyên sâu.

Cài đặt cơ bản Suricata từ mã nguồn.

Đối với những người thích tự biên dịch Suricata thay vì sử dụng các gói, quy trình trên các bản phân phối kiểu Debian/Ubuntu bao gồm việc đầu tiên cài đặt các gói phụ thuộc để biên dịch (build-essential, libpcre, libpcap-dev, libnet-dev, libyaml-dev, zlib, libcap-ng-dev, libjansson-dev, v.v.), tải xuống tệp nén tarball từ trang web chính thức và chạy các lệnh kinh điển ./configure, make, make install.

Trong giai đoạn cấu hình, tập lệnh sẽ cho biết các tính năng hỗ trợ nào đã được bật: AF_PACKET có/không, PF_RING, NFQUEUE có/không, NFLOG, IPFW, hỗ trợ cho libnss, libjansson, Prelude, PCRE JIT, Lua, GeoIP, v.v. Điều quan trọng là phải xác minh rằng NFQUEUE đã được bật nếu chúng ta muốn làm việc ở chế độ đó , và thư viện thu thập dữ liệu mà chúng ta quan tâm đã được tìm thấy.

Sau khi cài đặt tệp nhị phân, bạn có thể chạy lệnh `make install-conf` để triển khai cấu hình mặc định vào `/etc/suricata` và lệnh `make install-rules` để tải xuống và đặt một bộ quy tắc về các mối đe dọa mới nổi vào `/etc/suricata/rules`. Sau đó, bạn có thể cập nhật các bộ quy tắc này bằng các công cụ như `suricata-update`.

Trên các hệ thống Red Hat/CentOS, logic tương tự, sử dụng yum hoặc dnf để cài đặt các thư viện phụ thuộc (libpcap-devel, pcre-devel, libnet-devel, libyaml-devel, jansson-devel, v.v.) và sau đó biên dịch theo các bước tương tự. Vì lý do hiệu năng, cũng nên tắt LRO/GRO trong giao diện thu thập bằng ethtool, vì các chức năng giảm tải này có thể ảnh hưởng đến khả năng hiển thị của các gói ở cấp độ IDS.

Cấu hình Suricata: YAML, biến và đa luồng

Tệp cấu hình chính của Suricata nằm trong /etc/suricata/suricata.yaml . Đây là một tệp YAML khá dễ đọc và được chú thích kỹ lưỡng, trong đó định nghĩa mọi thứ từ đường dẫn nhật ký và bộ quy tắc đến chính sách hệ điều hành mục tiêu và các tham số luồng.

Một trong những trường cơ bản là `default-log-dir` , chỉ định nơi lưu trữ các tệp nhật ký (mặc định là `/var/log/suricata`). Trong phần `vars` là các biến như `HOME_NET`, `EXTERNAL_NET`, `HTTP_PORTS`, `SHELLCODE_PORTS` và `SSH_PORTS`, được dùng làm từ viết tắt trong các quy tắc. `HOME_NET` thường được cấu hình với phạm vi mạng cục bộ mà chúng ta muốn bảo vệ, trong khi `EXTERNAL_NET` thường được định nghĩa là `!HOME_NET`.

Một phần quan trọng khác là chính sách hệ điều hành máy chủ (host-os-policy) , cho Suricata biết hệ điều hành nào được phép chạy trên các dải địa chỉ IP nhất định. Điều này cho phép nó điều chỉnh cách lắp ráp lại TCP hoặc diễn giải các hành vi của ngăn xếp mạng , khiến việc né tránh các giao thức dựa trên sự khác biệt giữa các ngăn xếp (Windows so với Linux, v.v.) trở nên khó khăn hơn. Các dải địa chỉ cụ thể có thể được gán cho các danh mục như Windows, Linux, BSD, Vista, Windows 2003, v.v.

Về phần đa luồng, mục threading cho phép bạn tinh chỉnh độ ưu tiên CPU và số lượng luồng phát hiện. Theo mặc định, `set-cpu-affinity` thường bị vô hiệu hóa, cho phép bộ lập lịch hệ thống phân phối các luồng trên các lõi. Tham số `detect-thread-ratio` cho biết số lượng luồng phát hiện được tạo ra trên mỗi lõi khả dụng; với `detect-thread-ratio: 1.5` trên máy 8 lõi, Suricata sẽ tạo ra 12 luồng phát hiện, cộng với các luồng thu thập và quản lý.

Toàn bộ mô hình này sau đó được phản ánh trong đầu ra khi daemon khởi chạy: một luồng thu thập (ví dụ: pcap) và nhiều luồng dò tìm sẽ hiển thị, ngoài ra còn có các trình quản lý luồng và trình quản lý thống kê. Kiến trúc đa tiến trình này là điều cho phép Suricata mở rộng quy mô tốt hơn nhiều so với các công cụ đơn luồng khi đối mặt với các liên kết 10/40 Gbit/s.

Các quy định và cập nhật chữ ký tại Suricata

Suricata dựa vào các bộ quy tắc để phát hiện các kiểu tấn công, hành vi bất thường và việc lạm dụng giao thức. Ngoài việc chấp nhận các quy tắc ở định dạng Snort , hệ sinh thái phổ biến nhất là của Emerging Threats: ET Open (miễn phí) và ET Pro (thương mại), với các quy tắc hướng đến các mối đe dọa hiện tại.

Nhiều bản phân phối hiện đại bao gồm công cụ `suricata-update` , giúp đơn giản hóa việc quản lý quy tắc: nó cập nhật các nguồn, bật hoặc tắt các nhà cung cấp cụ thể và tải xuống các phiên bản mới nhất của bộ chữ ký. Quy trình làm việc điển hình là cài đặt `suricata-update` (ví dụ: thông qua pip), chạy `suricata-update` lần đầu tiên để tải xuống ET Open, liệt kê các nguồn bằng `suricata-update list-sources`, bật thêm các nguồn như `ptresearch/attackdetection`, `oisf/trafficid` hoặc `sslbl/ssl-fp-blacklist`, và chạy `suricata-update` một lần nữa để tạo lại tệp quy tắc.

Tệp suricata.yaml được điều chỉnh để trỏ đến đường dẫn quy tắc chính xác, và từ đó Suricata sẽ bắt đầu tạo ra các sự kiện cảnh báo được ghi lại trong fast.log (văn bản nhanh, dễ đọc) và eve.json (JSON có cấu trúc với thông tin rất đầy đủ) . Định dạng sau đặc biệt hữu ích để cung cấp dữ liệu cho bảng điều khiển, hệ thống tương quan hoặc các tập lệnh tùy chỉnh.

Ngoài chữ ký, Suricata còn tích hợp các bộ giải mã và phân tích cú pháp cho nhiều giao thức , cho phép nó ít phụ thuộc vào cổng hơn: nó có thể xác định lưu lượng HTTP ngay cả khi đi qua các cổng không chuẩn, phát hiện SSH, TLS, DNS, v.v. trên các cổng và mức độ đóng gói khác nhau (bao gồm cả các đường hầm IPv4/IPv6 hỗn hợp).

Ứng dụng thực tế: từ phát hiện các lỗ hổng bảo mật trên web đến chặn tự động.

Một trong những trường hợp sử dụng được mong muốn nhất trong môi trường lưu trữ hoặc trung tâm dữ liệu là phát hiện theo thời gian thực các nỗ lực khai thác lỗ hổng trong các ứng dụng web (ví dụ: WordPress và các plugin của nó) và tự động phản ứng, thường bằng cách chặn hoặc đưa địa chỉ IP nguồn vào danh sách đen trong tường lửa.

Suricata, được hỗ trợ bởi các quy tắc cập nhật, có khả năng nhận diện các mẫu tấn công cụ thể nhắm vào URL, tham số, tải trọng HTTP và thậm chí cả chuỗi yêu cầu phù hợp với các lỗ hổng đã biết. Hệ thống phát hiện xâm nhập (IDS) có thể hoạt động ở chế độ thụ động, nhận lưu lượng truy cập thông qua phản chiếu từ cổng chuyển mạch (SPAN), nhưng để hoạt động như một hệ thống ngăn chặn xâm nhập (IPS) và chặn các cuộc tấn công, nó cần được tích hợp với mặt phẳng chuyển tiếp.

Có hai cách tiếp cận phổ biến: thiết lập IDS như một cầu nối trực tuyến, sao cho lưu lượng truy cập vật lý đi qua máy (sử dụng iptables, AF_PACKET hoặc PF, tùy thuộc vào nền tảng), hoặc giữ nguyên cấu trúc mạng nhưng kết hợp sao chép với các hành động trên tường lửa trung tâm thông qua API, tập lệnh hoặc NFQUEUE . Cách tiếp cận đầu tiên giảm thiểu độ trễ giữa việc phát hiện và chặn, nhưng phải trả giá bằng việc thêm một yếu tố "ở giữa" mạng; cách thứ hai mang lại tính linh hoạt và khả năng phục hồi cao hơn, nhưng lại làm tăng độ phức tạp trong việc điều phối.

Hoàn toàn khả thi để một Hệ thống Phát hiện Xâm nhập (IDS) phát hiện nỗ lực khai thác lỗ hổng trong plugin WordPress và sau đó, trực tiếp hoặc thông qua một thành phần liên kết, thêm địa chỉ IP của kẻ tấn công vào danh sách đen iptables. Điều này có thể được thực hiện thông qua đầu ra JSON của Suricata và các tập lệnh gọi iptables/nftables , hoặc bằng cách ủy thác một số logic cho NFQUEUE, nơi chính công cụ hoặc một quy trình liên kết đưa ra quyết định ngay lập tức mà không cần chờ danh sách bên ngoài được cập nhật.

Điều này cho phép bạn tập trung vào các mối đe dọa thực sự quan trọng (các lỗ hổng bảo mật, các nỗ lực leo thang quyền truy cập, các cuộc quét rất mạnh), bỏ qua hoặc chỉ ghi lại những thông tin nhiễu nền như các cuộc quét cổng cơ bản mà trong nhiều trường hợp, bản thân chúng không đáng lo ngại.

Suricata trên Pfsense: tường lửa mã nguồn mở tích hợp hệ thống phát hiện và ngăn chặn xâm nhập (IDS/IPS).

Không phải ai cũng có đủ khả năng hoặc muốn mua một tường lửa cao cấp độc quyền như Palo Alto. Trong nhiều môi trường, việc thiết lập một giải pháp mã nguồn mở với pfSense và Suricata sẽ hấp dẫn hơn , vì nó đáp ứng cả nhu cầu tường lửa nâng cao (đa WAN, VLAN, VPN, NAT, v.v.) và IDS/IPS.

Pfsense, dựa trên FreeBSD và Packet Filter, hoạt động đặc biệt tốt với môi trường ảo hóa (Proxmox, KVM, v.v.), ngoại trừ việc nên sử dụng card E1000 thay vì Virtio trong máy KVM nếu muốn tránh các vấn đề về hiệu năng và sự cố sập hệ thống khi tải nặng, trừ khi bạn áp dụng các khuyến nghị của Netgate (vô hiệu hóa tính năng giảm tải kiểm tra tổng phần cứng trong Hệ thống > Nâng cao > Mạng và khởi động lại, cần lưu ý rằng điều này có thể không đủ với tải rất cao).

Yêu cầu phần cứng tối thiểu cho một phòng thí nghiệm với Suricata trên Pfsense có thể khá khiêm tốn (1 CPU 500 MHz, 1 GB RAM, 4 GB ổ cứng), nhưng để sử dụng nghiêm túc, ít nhất 2 CPU, 4 GB RAM và 16 GB dung lượng lưu trữ được khuyến nghị , đừng quên cần có một số giao diện mạng (một cho WAN, một cho LAN, nhiều hơn nếu bạn muốn có nhiều WAN hoặc VLAN phức tạp).

  Các biện pháp kiểm soát bảo mật trong WebRTC: hướng dẫn đầy đủ

Việc cài đặt pfSense diễn ra rất nhanh: bạn khởi động từ file ISO, chấp nhận giấy phép, chọn cài đặt, chọn ngôn ngữ và bố cục bàn phím, để phân vùng ở chế độ tự động (Auto UFS nếu bạn định sử dụng toàn bộ ổ đĩa), và chỉ trong vài phút hệ thống đã sẵn sàng cho lần khởi động đầu tiên. Giao diện dòng lệnh cung cấp một menu để gán giao diện, khởi động lại, khởi chạy shell, v.v.

Trong phòng thí nghiệm, ví dụ như trong VirtualBox, người ta thường tạm thời vô hiệu hóa tường lửa Pfsense từ bảng điều khiển bằng lệnh pfctl -d để truy cập giao diện web qua WAN (tên người dùng admin, mật khẩu pfsense) và hoàn tất trình hướng dẫn ban đầu: dữ liệu chung, máy chủ NTP, cấu hình WAN (thường thì DHCP là đủ trong phòng thí nghiệm), LAN, thay đổi mật khẩu quản trị và áp dụng cấu hình.

Sau khi thiết lập kết nối ổn định, bạn có thể tạo một quy tắc trong tường lửa WAN cho phép HTTPS từ bất kỳ nguồn nào đến địa chỉ IP của pfsense, thêm các dấu phân cách mô tả để sắp xếp các quy tắc một cách trực quan (ví dụ: "Truy cập tường lửa"). Bạn cũng nên tắt tùy chọn chặn mạng riêng trên WAN nếu đang ở trong môi trường thử nghiệm với địa chỉ RFC1918, để tránh phải liên tục sử dụng lệnh `pfctl -d`.

Cài đặt Suricata trên pfSense và tổng quan

Sau khi cài đặt và vận hành pfSense, việc cài đặt Suricata rất đơn giản, chỉ cần vào Hệ thống > Trình quản lý gói > Gói khả dụng , tìm kiếm Suricata và cài đặt gói. Quá trình này sẽ tải xuống một số tệp và có thể mất một thời gian tùy thuộc vào phần cứng của bạn, nhưng nó được hỗ trợ đầy đủ thông qua giao diện web.

Sau khi cài đặt, một mục Suricata sẽ xuất hiện trong tab Dịch vụ, nơi bạn có thể cấu hình các phiên bản theo giao diện (WAN, LAN, VLAN, v.v.), chọn bộ quy tắc cần sử dụng, kích hoạt chế độ IDS hoặc IPS và điều chỉnh các tham số hiệu suất và ghi nhật ký. Phạm vi tùy chọn rất rộng (đủ để viết cả bài báo chỉ về cấu hình), nhưng ưu điểm là nhiều tác vụ mà trong Linux yêu cầu chỉnh sửa YAML thủ công được xử lý ở đây bằng các biểu mẫu và hộp kiểm.

Lưu ý quan trọng: Mặc dù việc mở trực tiếp giao diện quản trị pfSense ra internet trong môi trường thử nghiệm có vẻ hấp dẫn, nhưng trong môi trường sản xuất, điều quan trọng là phải hạn chế quyền truy cập chỉ cho phép địa chỉ IP tĩnh, sử dụng VPN để quản lý từ xa và tránh để giao diện web bị lộ ra ngoài bằng mọi giá . pfSense rất linh hoạt, nhưng nó cũng phải được coi là một yếu tố quan trọng.

Khi Suricata được kích hoạt trên pfSense, bạn sẽ có một môi trường trong đó lưu lượng truy cập đi qua pfSense để thực hiện tường lửa và NAT, còn Suricata sẽ kiểm tra lưu lượng đó theo các quy tắc của nó và có thể chặn nó ở chế độ IPS . Sự kết hợp này, được quản lý từ một giao diện web duy nhất, giúp đơn giản hóa đáng kể việc triển khai bảo vệ DPI trong các mạng quy mô nhỏ và vừa.

Trong nhiều trường hợp triển khai, điều này được bổ sung bằng cách kết nối Pfsense/Suricata với SIEM hoặc nền tảng ghi nhật ký tập trung, tận dụng các định dạng đầu ra có cấu trúc để tương quan các sự kiện và phát hiện các chiến dịch quy mô lớn hơn.

Giám sát sự kiện và ví dụ về nhật ký trong Suricata

Sau khi Suricata khởi chạy, các sự kiện sẽ được ghi vào đường dẫn được xác định bởi default-log-dir, thường là /var/log/suricata . Tệp fast.log sử dụng định dạng văn bản nhỏ gọn với dấu thời gian, ID quy tắc, phân loại và mức độ ưu tiên, phù hợp để kiểm tra nhanh từ thiết bị đầu cuối (tail -f).

Ví dụ, khi gặp lưu lượng truy cập có tổng kiểm tra TCP không chính xác, chúng ta có thể thấy các dòng như sau: dấu thời gian với ngày và giờ, tiếp theo là mã định danh quy tắc (ví dụ: 1:2200074:1), thông báo "SURICATA TCPv4 invalid checksum", phân loại, mức độ ưu tiên và cặp địa chỉ IP/cổng nguồn-đích. Các loại cảnh báo này cho phép nhanh chóng xác định các vấn đề về tính toàn vẹn gói tin hoặc các nỗ lực né tránh.

Tệp eve.json chứa các sự kiện tương tự ở định dạng JSON, với các trường như timestamp, event_type, src_ip, dest_ip, src_port, dest_port, proto, và một tệp con alert với action, gid, signature_id, rev, signature, category và severity. Định dạng này có thể dễ dàng được tích hợp với Logstash, Fluentd, Filebeat hoặc bất kỳ tác nhân ghi nhật ký nào khác , cho phép phân tích chi tiết hơn nhiều so với việc chỉ sử dụng văn bản thuần túy.

Khi triển khai Suricata trên máy chủ đa lõi (ví dụ: 8 lõi), việc nén luồng sẽ dễ dàng nhận thấy trong các công cụ như htop ở chế độ luồng, hiển thị một hoặc nhiều luồng thu thập (pcap, AF_PACKET hoặc NFQ) và một số lượng lớn các luồng phát hiện được phân bổ trên các lõi. Điều chỉnh tỷ lệ luồng phát hiện và độ ưu tiên CPU có thể ảnh hưởng đáng kể đến thông lượng và độ trễ khi lưu lượng truy cập gần đạt đến giới hạn của nền tảng.

Trước khi triển khai vào môi trường sản xuất, bạn nên dành thời gian tinh chỉnh các bộ quy tắc nào được kích hoạt để tránh tình trạng quá tải các cảnh báo sai có thể chặn lưu lượng truy cập hợp pháp hoặc làm rối loạn nhật ký. Suricata-update cho phép bạn vô hiệu hóa toàn bộ danh mục hoặc các quy tắc riêng lẻ để tìm ra sự cân bằng hợp lý giữa độ nhạy và tính khả dụng.

Ứng dụng đặc biệt: VoIP, phân tích âm thanh và NFQUEUE sáng tạo

Ngoài những ứng dụng kinh điển (bảo vệ dịch vụ web, phát hiện phần mềm độc hại, phân tích DDoS), bộ đôi Netfilter+NFQUEUE cho phép tạo ra những giải pháp khá sáng tạo trong các lĩnh vực như VoIP. Ví dụ, có thể thiết lập bộ lọc chống SPIT (spam qua điện thoại IP) hoặc hệ thống kiểm duyệt từ ngữ tục tĩu trong luồng RTP.

Ý tưởng là: xác định lưu lượng RTP theo cổng hoặc theo nhận dạng giao thức và gửi nó đến NFQUEUE; từ ứng dụng người dùng, tái tạo luồng RTP bằng cách sử dụng thư viện như librtp , trích xuất âm thanh ở định dạng WAV và chuyển nó đến công cụ nhận dạng từ khóa (wordspotting), chẳng hạn như thư viện tổng hợp hoặc nhận dạng do bên thứ ba cung cấp.

Dựa trên các từ được phát hiện, tiến trình NFQUEUE có thể quyết định cho phép, chặn hoặc thậm chí thay đổi quá trình phát lại bằng cách chèn một tiếng bíp vào luồng dữ liệu, mặc dù điều này đòi hỏi sự kiểm soát rất tinh tế đối với RTCP, trình tự gói tin và thời gian—gần như là một phương pháp can thiệp trung gian. Điều này không hề đơn giản, nhưng về mặt lý thuyết, nó hoàn toàn có thể đạt được bằng cách tận dụng cùng một hệ thống hàng đợi và phán quyết.

Đúng là một số thao tác này có thể được thực hiện bằng một bộ phân tích gói tin đơn giản cung cấp dữ liệu cho bộ xử lý bên ngoài, sau đó xử lý tín hiệu SIP hoặc thông qua một SBC (Asterisk, Kamailio, v.v.). Sự khác biệt khi sử dụng NFQUEUE là thao tác trên luồng RTP có thể diễn ra ngay lập tức và trực tiếp , mà không cần phải phối hợp nhiều thành phần hoặc chờ lớp tín hiệu hoàn tất cuộc gọi.

Những tình huống này minh họa rõ ràng tiềm năng của sự kết hợp giữa GNU/Linux + Netfilter + Suricata + các thư viện của bên thứ ba: nó không chỉ đơn thuần là chặn các cổng và địa chỉ IP, mà còn là điều phối các quyết định lưu lượng truy cập phức tạp trong thời gian thực bằng cách sử dụng một hệ sinh thái phần mềm hoàn toàn miễn phí.

Nhìn vào toàn bộ quá trình, từ chương trình C nhỏ luôn chấp nhận gói tin đến hệ thống Suricata đa tiến trình tích hợp với NFQUEUE, Pfsense, cơ sở dữ liệu và bộ nhớ đệm, người ta có thể thấy được tính linh hoạt mà bộ công nghệ này mang lại để xây dựng mọi thứ, từ tường lửa động đơn giản đến kiến ​​trúc IDS/IPS quy mô trung tâm dữ liệu, với khả năng kiểm tra chuyên sâu thực sự và phản hồi tự động đối với các cuộc tấn công ngày càng phức tạp.