Cách triển khai mẫu firewall cơ bản với Iptables trên Ubuntu 14.04
Triển khai firewall là một bước quan trọng trong việc bảo mật server của bạn. Một phần lớn trong số đó là quyết định các luật và policy riêng lẻ sẽ thực thi các giới hạn lưu lượng truy cập vào mạng của bạn. Tường lửa nhưiptables
cũng cho phép bạn nói về khung cấu trúc mà các luật của bạn được áp dụng. Trong hướng dẫn này, ta sẽ xây dựng một bức firewall có thể là cơ sở cho các bộ luật phức tạp hơn. Tường lửa này sẽ tập trung chủ yếu vào việc cung cấp các giá trị mặc định hợp lý và cài đặt một khuôn khổ khuyến khích khả năng mở rộng dễ dàng. Ta sẽ chứng minh điều này trên server Ubuntu 14.04.
Yêu cầu
Trước khi bắt đầu, bạn nên có ý tưởng cơ bản về các policy firewall mà bạn muốn thực hiện. Bạn có thể làm theo hướng dẫn này để hiểu rõ hơn về một số điều bạn nên suy nghĩ.
Để làm theo, bạn cần có quyền truy cập vào server Ubuntu 14.04. Ta sẽ sử dụng user không phải root được cấu hình với các quyền sudo
trong suốt hướng dẫn này. Bạn có thể tìm hiểu cách cấu hình loại user này trong hướng dẫn cài đặt server ban đầu Ubuntu 14.04 của ta .
Khi bạn hoàn thành, hãy tiếp tục bên dưới.
Cài đặt dịch vụ firewall liên tục
Để bắt đầu, bạn cần cài đặt gói iptables-persistent
nếu bạn chưa thực hiện. Điều này sẽ cho phép ta lưu các bộ luật của bạn và tự động áp dụng chúng khi khởi động:
- sudo apt-get update
- sudo apt-get install iptables-persistent
Trong khi cài đặt, bạn sẽ được hỏi có muốn lưu các luật hiện tại của bạn hay không. Nói "có" ở đây. Ta sẽ chỉnh sửa các file luật đã tạo trong giây lát.
Lưu ý về IPv6 trong Hướng dẫn này
Trước khi bắt đầu, ta nên nói sơ qua về IPv4 và IPv6. Lệnh iptables
chỉ xử lý lưu lượng IPv4. Đối với lưu lượng IPv6, một công cụ đồng hành riêng biệt được gọi là ip6tables
được sử dụng. Các luật được lưu trữ trong các bảng và chuỗi riêng biệt. Đối với iptables-persistent
, các luật IPv4 được ghi và đọc từ /etc/iptables/rules.v4
và các luật IPv6 được giữ trong /etc/iptables/rules.v6
.
Hướng dẫn này giả định bạn không tích cực sử dụng IPv6 trên server của bạn . Nếu dịch vụ của bạn không tận dụng IPv6, thì sẽ an toàn hơn nếu bạn chặn hoàn toàn quyền truy cập, như ta sẽ thực hiện trong bài viết này.
Thực hiện policy firewall cơ bản (Cách nhanh chóng)
Để cài đặt và chạy nhanh nhất có thể, ta sẽ hướng dẫn bạn cách chỉnh sửa trực tiếp file luật để copy paste policy firewall đã hoàn thành. Sau đó, ta sẽ giải thích chiến lược chung và chỉ cho bạn cách thực hiện các luật này bằng lệnh iptables
thay vì sửa đổi file .
Để thực hiện policy firewall của ta và khuôn khổ, ta sẽ chỉnh sửa /etc/iptables/rules.v4
và /etc/iptables/rules.v6
file . Mở file rules.v4
trong editor của bạn với các quyền sudo
:
- sudo nano /etc/iptables/rules.v4
Bên trong, bạn sẽ thấy một file trông giống như sau:
# Generated by iptables-save v1.4.21 on Tue Jul 28 13:29:56 2015 *filter :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] COMMIT # Completed on Tue Jul 28 13:29:56 2015
Thay thế nội dung bằng:
*filter # Allow all outgoing, but drop incoming and forwarding packets by default :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] # Custom per-protocol chains :UDP - [0:0] :TCP - [0:0] :ICMP - [0:0] # Acceptable UDP traffic # Acceptable TCP traffic -A TCP -p tcp --dport 22 -j ACCEPT # Acceptable ICMP traffic # Boilerplate acceptance policy -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT -A INPUT -i lo -j ACCEPT # Drop invalid packets -A INPUT -m conntrack --ctstate INVALID -j DROP # Pass traffic to protocol-specific chains ## Only allow new connections (established and related should already be handled) ## For TCP, additionally only allow new SYN packets since that is the only valid ## method for establishing a new TCP connection -A INPUT -p udp -m conntrack --ctstate NEW -j UDP -A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP -A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP # Reject anything that's fallen through to this point ## Try to be protocol-specific w/ rejection message -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable -A INPUT -p tcp -j REJECT --reject-with tcp-reset -A INPUT -j REJECT --reject-with icmp-proto-unreachable # Commit the changes COMMIT *raw :PREROUTING ACCEPT [0:0] :OUTPUT ACCEPT [0:0] COMMIT *nat :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] COMMIT *security :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] COMMIT *mangle :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] COMMIT
Lưu và đóng file .
Bạn có thể kiểm tra file để tìm lỗi cú pháp bằng lệnh lệnh này. Sửa bất kỳ lỗi cú pháp nào mà lỗi này tiết lộ trước khi tiếp tục:
- sudo iptables-restore -t /etc/iptables/rules.v4
Tiếp theo, mở file /etc/iptables/rules.v6
để sửa đổi các luật IPv6:
- sudo nano /etc/iptables/rules.v6
Ta có thể chặn tất cả lưu lượng IPv6 bằng cách thay thế nội dung của file bằng cấu hình bên dưới:
*filter :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT DROP [0:0] COMMIT *raw :PREROUTING DROP [0:0] :OUTPUT DROP [0:0] COMMIT *nat :PREROUTING DROP [0:0] :INPUT DROP [0:0] :OUTPUT DROP [0:0] :POSTROUTING DROP [0:0] COMMIT *security :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT DROP [0:0] COMMIT *mangle :PREROUTING DROP [0:0] :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT DROP [0:0] :POSTROUTING DROP [0:0] COMMIT
Lưu và đóng file .
Để kiểm tra lỗi cú pháp cho file này, ta có thể sử dụng lệnh ip6tables-restore
với tùy chọn -t
:
- sudo ip6tables-restore -t /etc/iptables/rules.v6
Khi cả hai file luật đều báo cáo không có lỗi cú pháp, bạn có thể áp dụng các luật bên trong bằng lệnh :
- sudo service iptables-persistent reload
Điều này sẽ ngay lập tức triển khai policy được nêu trong file của bạn. Bạn có thể xác minh điều này bằng cách liệt kê các luật iptables
hiện đang được sử dụng:
- sudo iptables -S
- sudo ip6tables -S
Các luật firewall này sẽ được áp dụng lại mỗi lần khởi động. Kiểm tra đảm bảo rằng bạn vẫn có thể đăng nhập và tất cả các quyền truy cập khác đã bị chặn.
Giải thích về Chiến lược Tường lửa Chung của Ta
Trong firewall cơ bản mà ta đã xây dựng với các luật trên, ta đã tạo một khung có thể mở rộng có thể dễ dàng điều chỉnh để thêm hoặc xóa các luật . Đối với lưu lượng IPv4, ta chủ yếu quan tâm đến chuỗi INPUT
trong bảng filter
. Chuỗi này sẽ xử lý tất cả các gói dành cho server của ta . Ta cũng đã cho phép tất cả lưu lượng gửi đi và từ chối tất cả chuyển tiếp gói, điều này sẽ chỉ phù hợp nếu server này hoạt động như một bộ định tuyến cho các server khác. Ta chấp nhận các gói trong tất cả các bảng khác vì ta chỉ tìm cách lọc các gói trong hướng dẫn này.
Nói chung, các luật của ta cài đặt một firewall sẽ từ chối lưu lượng đến theo mặc định. Sau đó, ta bắt đầu tạo ngoại lệ cho các dịch vụ và loại lưu lượng mà ta muốn loại trừ khỏi policy này.
Trong chuỗi INPUT
chính, ta đã thêm một số luật chung cho lưu lượng truy cập mà ta tin rằng sẽ luôn được xử lý theo cùng một cách. Ví dụ: ta luôn muốn từ chối các gói được coi là “không hợp lệ” và ta sẽ luôn muốn cho phép lưu lượng truy cập trên giao diện loopback local và dữ liệu được liên kết với kết nối đã cài đặt .
Sau đó, ta đối sánh lưu lượng truy cập dựa trên giao thức mà nó đang sử dụng và trộn nó vào một chuỗi giao thức cụ thể. Các chuỗi giao thức cụ thể này nghĩa là giữ các luật phù hợp và cho phép lưu lượng truy cập cho các dịch vụ cụ thể. Trong ví dụ này, dịch vụ duy nhất mà ta cho phép là SSH trong chuỗi TCP
của ta . Nếu ta cung cấp một dịch vụ khác, chẳng hạn như server HTTP (S), ta cũng có thể thêm các ngoại lệ tại đây. Các chuỗi này sẽ là trọng tâm của hầu hết các tùy chỉnh của bạn.
Bất kỳ lưu lượng nào không phù hợp với luật chung hoặc luật dịch vụ trong giao thức cụ thể sẽ được xử lý bởi một số luật cuối cùng trong chuỗi INPUT
. Ta đã đặt policy mặc định thành DROP
cho firewall của ta , policy này sẽ từ chối các gói nằm trong luật của ta . Tuy nhiên, các luật ở cuối chuỗi INPUT
từ chối các gói và gửi thông báo đến client mô phỏng cách server sẽ phản hồi nếu không có dịch vụ nào chạy trên cổng đó.
Đối với lưu lượng IPv6, ta chỉ cần loại bỏ tất cả lưu lượng. Server của ta không sử dụng giao thức này, vì vậy an toàn nhất là không tham gia vào lưu lượng truy cập.
(Tùy chọn) Cập nhật server tên
Việc chặn tất cả lưu lượng IPv6 có thể ảnh hưởng đến cách server của bạn giải quyết mọi thứ trên Internet. Ví dụ: điều này có thể ảnh hưởng đến cách bạn sử dụng APT.
Nếu bạn gặp lỗi như thế này khi bạn cố gắng chạy apt-get update
:
Err http://security.ubuntu.com trusty-security InRelease Err http://security.ubuntu.com trusty-security Release.gpg Could not resolve 'security.ubuntu.com' . . .
Bạn nên làm theo phần này để APT hoạt động trở lại.
Đầu tiên, đặt server định danh của bạn thành server định danh bên ngoài. Ví dụ này sử dụng server định danh của Google. Mở /etc/network/interfaces
để chỉnh sửa:
- sudo nano /etc/network/interfaces
Cập nhật dòng dns-nameservers
như hình:
. . . iface eth0 inet6 static address 2604:A880:0800:0010:0000:0000:00B2:0001 netmask 64 gateway 2604:A880:0800:0010:0000:0000:0000:0001 autoconf 0 dns-nameservers 8.8.8.8 8.8.4.4
Làm mới cài đặt mạng của bạn:
- sudo ifdown eth0 && sudo ifup eth0
Sản lượng mong đợi là:
RTNETLINK answers: No such process Waiting for DAD... Done
Tiếp theo, tạo luật firewall mới để buộc IPv4 khi có sẵn. Tạo file mới này:
- sudo nano /etc/apt/apt.conf.d/99force-ipv4
Thêm dòng đơn này vào file :
Acquire::ForceIPv4 "true";
Lưu và đóng file . Đến đây bạn sẽ có thể sử dụng APT.
Triển khai firewall của ta bằng lệnh IPTables
Đến đây bạn đã hiểu ý tưởng chung đằng sau policy mà ta đã xây dựng, ta sẽ hướng dẫn bạn cách tạo các luật đó bằng cách sử dụng các lệnh iptables
. Ta sẽ kết thúc với các luật tương tự mà ta đã chỉ định ở trên nhưng ta sẽ tạo các policy của bạn bằng cách thêm các luật lặp đi lặp lại. Bởi vì iptables
áp dụng từng luật ngay lập tức, thứ tự luật là rất quan trọng ( ta để nguyên luật từ chối gói cho đến cuối).
Đặt lại firewall của bạn
Ta sẽ bắt đầu bằng cách đặt lại các luật firewall của bạn để ta có thể xem cách các policy có thể được xây dựng từ dòng lệnh. Bạn có thể xóa tất cả các luật của bạn bằng lệnh :
- sudo service iptables-persistent flush
Bạn có thể xác minh các luật của bạn đã được đặt lại bằng lệnh :
- sudo iptables -S
Bạn sẽ thấy rằng các luật trong bảng filter
đã biến mất và policy mặc định được đặt thành ACCEPT
trên tất cả các chuỗi:
output-P INPUT ACCEPT -P FORWARD ACCEPT -P OUTPUT ACCEPT
Tạo chuỗi dành riêng cho giao thức
Ta sẽ bắt đầu bằng cách tạo tất cả các chuỗi giao thức cụ thể của ta . Những điều này sẽ được sử dụng để giữ các luật tạo ngoại lệ cho policy từ chối của ta đối với các dịch vụ mà ta muốn tiết lộ. Ta sẽ tạo một cho lưu lượng UDP
, một cho TCP
và một cho ICMP
:
- sudo iptables -N UDP
- sudo iptables -N TCP
- sudo iptables -N ICMP
Ta có thể tiếp tục và thêm ngoại lệ cho lưu lượng SSH. SSH sử dụng TCP, vì vậy ta sẽ thêm một luật để chấp nhận lưu lượng TCP dành cho cổng 22 vào chuỗi TCP:
- sudo iptables -A TCP -p tcp --dport 22 -j ACCEPT
Nếu ta muốn thêm các dịch vụ TCP bổ sung, ta có thể làm điều đó ngay bây giờ bằng cách lặp lại lệnh với số cổng được thay thế.
Tạo Luật Chấp nhận và Từ chối Mục đích Chung
Trong chuỗi INPUT
, nơi tất cả lưu lượng đến bắt đầu lọc, ta cần thêm các luật mục đích chung của bạn . Đây là một số luật thông thường cài đặt đường cơ sở cho firewall của ta bằng cách chấp nhận lưu lượng truy cập có rủi ro thấp (lưu lượng truy cập local và lưu lượng liên kết với các kết nối mà ta đã kiểm tra) và loại bỏ lưu lượng truy cập rõ ràng là không hữu ích (gói không hợp lệ).
Đầu tiên, ta sẽ tạo một ngoại lệ để chấp nhận tất cả lưu lượng là một phần của kết nối đã cài đặt hoặc có liên quan đến kết nối đã cài đặt :
- sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
Luật này sử dụng trình mở rộng conntrack
, cung cấp tính năng theo dõi nội bộ để iptables
có ngữ cảnh cần thiết để đánh giá các gói như một phần của các kết nối lớn hơn thay vì dưới dạng một stream các gói rời rạc, không liên quan. TCP là một giao thức dựa trên kết nối, vì vậy một kết nối đã cài đặt được xác định khá rõ ràng. Đối với UDP và các giao thức không kết nối khác, các kết nối được cài đặt đề cập đến lưu lượng đã thấy phản hồi (nguồn của gói ban đầu sẽ là đích của gói phản hồi và ngược lại). Một kết nối liên quan đề cập đến một kết nối mới đã được khởi tạo cùng với một kết nối hiện có. Ví dụ cổ điển ở đây là kết nối truyền dữ liệu FTP, kết nối này sẽ liên quan đến kết nối điều khiển FTP đã được cài đặt .
Ta cũng muốn cho phép tất cả lưu lượng truy cập có nguồn root trên giao diện loopback local . Đây là lưu lượng do server tạo ra và dành cho server . Nó được các dịch vụ trên server sử dụng để giao tiếp với nhau:
- sudo iptables -A INPUT -i lo -j ACCEPT
Cuối cùng, ta muốn từ chối tất cả các gói không hợp lệ. Các gói có thể không hợp lệ vì một số lý do. Chúng có thể đề cập đến các kết nối không tồn tại, chúng có thể được dành cho các giao diện, địa chỉ hoặc cổng không tồn tại hoặc chúng có thể đơn giản là không đúng định dạng. Trong mọi trường hợp, ta sẽ loại bỏ tất cả các gói không hợp lệ vì không có cách thích hợp để xử lý chúng và vì chúng có thể đại diện cho hoạt động độc hại:
- sudo iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
Tạo Luật Chuyển sang Chuỗi dành riêng cho Giao thức
Lúc này, ta đã tạo ra một số luật chung trong chuỗi INPUT
và một số luật cho các dịch vụ được chấp nhận cụ thể trong chuỗi giao thức cụ thể của ta . Tuy nhiên, hiện tại, lưu lượng truy cập vào chuỗi INPUT
và không có cách nào để tiếp cận chuỗi giao thức cụ thể của ta .
Ta cần hướng lưu lượng truy cập trong chuỗi INPUT
vào các chuỗi giao thức cụ thể thích hợp. Ta có thể đối sánh loại giao thức để gửi nó đến đúng chuỗi. Ta cũng sẽ đảm bảo gói tin đại diện cho một kết nối mới (bất kỳ kết nối nào đã được cài đặt hoặc có liên quan nên đã được xử lý trước đó). Đối với gói TCP, ta sẽ thêm yêu cầu bổ sung rằng gói đó là gói SYN, là loại hợp lệ duy nhất để bắt đầu kết nối TCP:
- sudo iptables -A INPUT -p udp -m conntrack --ctstate NEW -j UDP
- sudo iptables -A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP
- sudo iptables -A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP
Từ chối tất cả lưu lượng truy cập còn lại
Nếu một gói được chuyển đến một chuỗi giao thức cụ thể không trùng với bất kỳ luật nào bên trong, thì quyền kiểm soát sẽ được chuyển trở lại chuỗi INPUT
. Bất kỳ thứ gì đạt đến điểm này sẽ không được phép bởi firewall của ta .
Ta sẽ từ chối lưu lượng truy cập bằng cách sử dụng mục tiêu REJECT
, mục tiêu này sẽ gửi thông báo phản hồi đến client . Điều này cho phép ta chỉ định thông báo gửi đi để ta có thể bắt chước phản hồi sẽ được đưa ra nếu khách hàng cố gắng gửi các gói đến một cổng đóng thông thường. Phản hồi phụ thuộc vào giao thức được sử dụng bởi client .
Cố gắng truy cập cổng UDP đã đóng sẽ dẫn đến thông báo ICMP “cổng không thể truy cập”. Ta có thể bắt chước điều này bằng lệnh :
- sudo iptables -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
Cố gắng cài đặt kết nối TCP trên một cổng đã đóng dẫn đến phản hồi TCP RST:
- sudo iptables -A INPUT -p tcp -j REJECT --reject-with tcp-reset
Đối với tất cả các gói khác, ta có thể gửi thông báo ICMP “giao thức không thể truy cập” để cho biết server không phản hồi với các gói thuộc loại đó:
- sudo iptables -A INPUT -j REJECT --reject-with icmp-proto-unreachable
Điều chỉnh policy mặc định
Ba luật cuối cùng mà ta đã thêm sẽ xử lý tất cả lưu lượng còn lại trong chuỗi INPUT
. Tuy nhiên, ta nên đặt policy mặc định thành DROP
để đề phòng. Ta cũng nên đặt policy này trong chuỗi FORWARD
nếu server này không được cấu hình làm bộ định tuyến cho các máy khác:
- sudo iptables -P INPUT DROP
- sudo iptables -P FORWARD DROP
DROP
, nếu bạn xóa iptables
của bạn bằng sudo iptables -F
, kết nối SSH hiện tại của bạn sẽ bị ngắt! Xóa bằng sudo iptables-persistent flush
là cách tốt hơn để xóa các luật vì nó cũng sẽ đặt lại policy mặc định. Để phù hợp với policy IPv6 của ta về việc loại bỏ tất cả lưu lượng truy cập, ta có thể sử dụng các lệnh ip6tables
sau:
- sudo ip6tables -P INPUT DROP
- sudo ip6tables -P FORWARD DROP
- sudo ip6tables -P OUTPUT DROP
Điều này sẽ lặp lại các luật của ta khá chặt chẽ.
Lưu luật IPTables
Đến đây, bạn nên kiểm tra các luật firewall của bạn và đảm bảo các luật này đã chặn được lưu lượng truy cập mà bạn muốn giữ lại trong khi không cản trở việc truy cập thông thường của bạn. Khi thấy ổn rằng các luật của bạn đang hoạt động chính xác, bạn có thể lưu chúng để chúng tự động được áp dụng cho hệ thống của bạn khi khởi động.
Lưu các luật hiện tại của bạn (cả IPv4 và IPv6) bằng lệnh :
- sudo service iptables-persistent save
Thao tác này sẽ overrides các file /etc/iptables/rules.v6
và /etc/iptables/rules.v4
của bạn bằng các policy bạn đã tạo trên dòng lệnh.
Kết luận
Theo hướng dẫn này, bằng cách dán trực tiếp các luật firewall của bạn vào file cấu hình hoặc bằng cách áp dụng và lưu chúng theo cách thủ công trên dòng lệnh, bạn đã tạo được cấu hình firewall khởi đầu tốt. Bạn sẽ phải thêm các luật riêng lẻ để cho phép truy cập vào các dịch vụ bạn muốn cung cấp.
Khuôn khổ được cài đặt trong hướng dẫn này sẽ cho phép bạn dễ dàng thực hiện các điều chỉnh và có thể giúp làm rõ các policy hiện có của bạn. Xem một số hướng dẫn khác của ta để biết cách xây dựng policy firewall của bạn với một số dịch vụ phổ biến:
- Iptables Essentials: Các luật và lệnh firewall chung
- Cách cài đặt firewall Iptables để bảo vệ lưu lượng truy cập giữa các server của bạn
- Cách chuyển tiếp cổng thông qua cổng Linux với Iptables
- Cách kiểm tra cấu hình firewall của bạn với Nmap và Tcpdump
Các tin liên quan
Cách thiết lập firewall Iptables để bảo vệ lưu lượng truy cập giữa các server của bạn2015-08-20
Tìm hiểu sâu về kiến trúc Iptables và Netfilter
2015-08-20
Cách di chuyển từ FirewallD sang Iptables trên CentOS 7
2015-08-20
Cách liệt kê và xóa các quy tắc firewall Iptables
2015-08-14
Iptables Essentials: Các quy tắc và lệnh firewall chung
2015-08-10
Cách cô lập server trong mạng riêng bằng Iptables
2014-06-04
Cách thiết lập firewall bằng Iptables trên Ubuntu 14.04
2014-05-06
Cách thức hoạt động của firewall Iptables
2014-05-02
Cách thiết lập firewall Iptables cơ bản trên Centos 6
2013-04-16
Cách thiết lập firewall Iptables cơ bản trên Centos 6
2013-04-16