Phần này sẽ trình bày qua ví dụ cụ thể và chỉ hướng dẫn các bạn lọc packet vào. Các packet “forward” và “output” tương tự. Giả sử như máy chủ phục vụ Web kết nối mạng trực tiếp vào Internet qua card mạng eth0, địa chỉ IP là 1.2.3.4. Cần lập cấu hình tường lửa cho Iptables đáp ứng các yêu cầu sau: - Cổng TCP 80 (chạy apache) mở cho mọi người truy cập web - Cổng 21 (chạy proftpd) chỉ mở cho webmaster (dùng để upload file lên public_html) - Cổng 22 (chạy openssh) chỉ mở cho admin (cung cấp shell `root` cho admin để nâng cấp & patch lỗi cho server khi cần) - Cổng UDP 53 (chạy tinydns) để phục vụ tên miền (đây chỉ là ví dụ) - Chỉ chấp nhận ICMP PING tới với code=0×08, các loại packet còn lại đều bị từ chối. Bước 1: thiết lập các tham số cho nhân echo 1 > /proc/sys/net/ipv4/tcp_syncookies echo 10 > /proc/sys/net/ipv4/tcp_fin_timeout echo 1800 > /proc/sys/net/ipv4/tcp_keepalive_time echo 0 > /proc/sys/net/ipv4/tcp_window_scaling echo 0 > /proc/sys/net/ipv4/tcp_sack echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts echo 0 > /proc/sys/net/ipv4/conf/eth0/accept_source_route tcp_syncookies=1 bật chức năng chống DoS SYN qua syncookie của Linux tcp_fin_timeout=10 đặt thời gian timeout cho quá trình đóng kết nối TCP là 10 giây tcp_keepalive_time=1800 đặt thời gian giữ kết nối TCP là 1800 giây … Các tham số khác bạn có thể xem chi tiết trong tài liệu đi kèm của nhân Linux. Bước 2: nạp các môđun cần thiết cho Iptables Để sử dụng Iptables, bạn cần phải nạp trước các môđun cần thiết. Ví dụ nếu bạn muốn dùng chức năng LOG trong Iptables, bạn phải nạp môđun ipt_LOG vào trước bằng lệnh # modprobe ipt_LOG. MODULES=”ip_tables iptable_filter ipt_LOG ipt_limit ipt_REJECT ipt_state for i in $MODULES; do /sbin/modprobe $MODULES done Bước 3: nguyên tắc đặt luật là “drop trước, accept sau” Đây là nguyên tắc mà bạn nên tuân theo. Đầu tiên hãy đóng hết các cổng, sau đó mở dần cách cổng cần thiết. Cách này tránh cho bạn gặp sai sót trong khi đặt luật cho Iptables. iptables -P INPUT DROP thả packet trước iptables -A INPUT -m state –state ESTABLISHED,RELATED -j ACCEPT giữ các kết nối hiện tại và chấp nhận các kết nối có liên quan iptables -A INPUT -i lo -s 127.0.0.1 -j ACCEPT chấp nhận các gói vào looback từ IP 127.0.0.1 iptables -A INPUT -i lo -s 1.2.3.4 -j ACCEPT và 1.2.3.4 BANNED_IP=”10.0.0.0/8 192.168.0.0/16 172.16.0.0/12 224.0.0.0/4 240.0.0.0/5″ for i in $BANNED_IP; do iptables -A INPUT -i eth0 -s $i -j DROP thả các gói dữ liệu đến từ các IP nằm trong danh sách cấm BANNER_IP done Bước 4: lọc ICMP vào và chặn ngập lụt PING LOG của Iptables sẽ được ghi vào file /var/log/firewall.log. Bạn phải sửa lại cấu hình cho SYSLOG như sau: # vi /etc/syslog.conf kern.=debug /var/log/firewall.log # /etc/rc.d/init.d/syslogd restart Đối với các gói ICMP đến, chúng ta sẽ đẩy qua chain CHECK_PINGFLOOD để kiểm tra xem hiện tại đamg bị ngập lụt PING hay không, sau đó mới cho phép gói vào. Nếu đang bị ngập lụt PING, môđun LOG sẽ tiến hành ghi nhật kí ở mức giới hạn –limit $LOG_LIMIT và –limit-burst $LOG_LIMIT_BURST, các gói PING ngập lụt sẽ bị thả hết. LOG_LEVEL=”debug” LOG_LIMIT=3/m LOG_LIMIT_BURST=1 PING_LIMIT=500/s PING_LIMIT_BURST=100 iptables -A CHECK_PINGFLOOD -m limit –limit $PING_LIMIT –limit-burst $PING_LIMIT_BURST -j RETURN iptables -A CHECK_PINGFLOOD -m limit –limit $LOG_LIMIT –limit-burst $LOG_LIMIT_BURST -j LOG –log-level $LOG_LEVEL –log-prefix “fp=PINGFLOOD:warning a=DROP ” iptables -A CHECK_PINGFLOOD -j DROP iptables -A INPUT -i eth0 -p icmp –icmp-type echo-request -j CHECK_PINGFLOOD iptables -A INPUT -i eth0 -p icmp –icmp-type echo-request -j ACCEPT Bước 5: reject quét cổng TCP và UDP Ở đây bạn tạo sẵn chain reject quét cổng, chúng ta sẽ đẩy vào chain INPUT sau. Đối với gói TCP, chúng ta reject bằng gói TCP với cờ SYN=1 còn đối với gói UDP, chúng ta sẽ reject bằng gói ICMP `port-unreachable` iptables-N REJECT_PORTSCAN iptables-A REJECT_PORTSCAN -p tcp -m limit –limit $LOG_LIMIT –limit-burst $LOG_LIMIT_BURST -j LOG –log-level $LOG_LEVEL –log-prefix “fp=PORTSCAN:tcp a=REJECT ” iptables-A REJECT_PORTSCAN -p udp -m limit –limit $LOG_LIMIT –limit-burst $LOG_LIMIT_BURST -j LOG –log-level $LOG_LEVEL –log-prefix “fp=PORTSCAN:udp a=REJECT ” iptables-A REJECT_PORTSCAN -p tcp -j REJECT –reject-with tcp-reset iptables-A REJECT_PORTSCAN -p udp -j REJECT –reject-with icmp-port-unreachable Bước 6: phát hiện quét cổng bằng Nmap iptables-N DETECT_NMAP iptables-A DETECT_NMAP -p tcp –tcp-flags ALL FIN,URG,PSH -m limit –limit $LOG_LIMIT – limit-burst $LOG_LIMIT_BURST -j LOG –log-level $LOG_LEVEL –log-prefix “fp=NMAP:XMAS a=DROP ” iptables-A DETECT_NMAP -p tcp –tcp-flags ALL SYN,RST,ACK,FIN,URG -m limit –limit $LOG_LIMIT –limit-burst $LOG_LIMIT_BURST -j LOG –log-level $LOG_LEVEL –log-prefix “fp=NMAP:XMAS-PSH a=DROP ” iptables-A DETECT_NMAP -p tcp –tcp-flags ALL ALL -m limit –limit $LOG_LIMIT –limit-burst $LOG_LIMIT_BURST -j LOG –log-level $LOG_LEVEL –log-prefix “fp=NMAP:XMAS-ALL a=DROP ” iptables-A DETECT_NMAP -p tcp –tcp-flags ALL FIN -m limit –limit $LOG_LIMIT –limit-burst $LOG_LIMIT_BURST -j LOG –log-level $LOG_LEVEL –log-prefix “fp=NMAP:FIN a=DROP ” iptables-A DETECT_NMAP -p tcp –tcp-flags SYN,RST SYN,RST -m limit –limit $LOG_LIMIT – limit-burst $LOG_LIMIT_BURST -j LOG –log-level $LOG_LEVEL –log-prefix “fp=NMAP:SYN-RST a=DROP ” iptables-A DETECT_NMAP -p tcp –tcp-flags SYN,FIN SYN,FIN -m limit –limit $LOG_LIMIT – limit-burst $LOG_LIMIT_BURST -j LOG –log-level $LOG_LEVEL –log-prefix “fp=NMAP:SYN-FIN a=DROP ” iptables-A DETECT_NMAP -p tcp –tcp-flags ALL NONE -m limit –limit $LOG_LIMIT –limit-burst $LOG_LIMIT_BURST -j LOG –log-level $LOG_LEVEL –log-prefix “fp=NMAP:NULL a=DROP ” iptables-A DETECT_NMAP -j DROP iptables-A INPUT -i eth0 -p tcp ! –syn -m state –state NEW -j DETECT_NMAP Đối với các gói TCP đến eth0 mở kết nối nhưng không đặt SYN=1 chúng ta sẽ chuyển sang chain DETECT_NMAP. Đây là những gói không hợp lệ và hầu như là quét cổng bằng nmap hoặc kênh ngầm. Chain DETECT_NMAP sẽ phát hiện ra hầu hết các kiểu quét của Nmap và tiến hành ghi nhật kí ở mức –limit $LOG_LIMIT và –limit-burst $LOG_LIMIT_BURST. Ví dụ để kiểm tra quét XMAS, bạn dùng tùy chọn –tcp-flags ALL FIN,URG,PSH nghĩa là 3 cờ FIN, URG và PSH được bật, các cờ khác đều bị tắt. Các gói qua chain DETECT_NMAP sau đó sẽ bị DROP hết. Bước 7: chặn ngập lụt SYN Gói mở TCP với cờ SYN được set 1 là hợp lệ nhưng không ngoại trừ khả năng là các gói SYN dùng để ngập lụt. Vì vậy, ở dây bạn đẩy các gói SYN còn lại qua chain CHECK_SYNFLOOD để kiểm tra ngập lụt SYN như sau: iptables-N CHECK_SYNFLOOD iptables-A CHECK_SYNFLOOD -m limit –limit $SYN_LIMIT –limit-burst $SYN_LIMIT_BURST -j RETURN iptables-A CHECK_SYNFLOOD -m limit –limit $LOG_LIMIT –limit-burst $LOG_LIMIT_BURST -j LOG –log-level $LOG_LEVEL –log-prefix “fp=SYNFLOOD:warning a=DROP ” iptables-A CHECK_SYNFLOOD -j DROP iptables-A INPUT -i eth0 -p tcp –syn -j CHECK_SYNFLOOD Bước 8: giới hạn truy cập SSH cho admin SSH_IP=”1.1.1.1″ iptables -N SSH_ACCEPT iptables -A SSH_ACCEPT -m state –state NEW -j LOG –log-level $LOG_LEVEL –log-prefix “fp=SSH:admina=ACCEPT ” iptables -A SSH_ACCEPT -j ACCEPT iptables -N SSH_DENIED iptables -A SSH_DENIED -m limit –limit $LOG_LIMIT –limit-burst $LOG_LIMIT_BURST -j LOG – log-level $LOG_LEVEL –log-prefix “fp=SSH:attempt a=REJECT ” iptables -A SSH_DENIED -p tcp -j REJECT –reject-with tcp-reset for i in $SSH_IP; do iptables -A INPUT -i eth0 -p tcp -s $i –dport 22 -j SSH_ACCEPT done iptables -A INPUT -i eth0 -p tcp –dport 22 -m state –state NEW -j SSH_DENIED Bước 9: giới hạn FTP cho web-master FTP_IP=”2.2.2.2″ iptables -N FTP_ACCEPT iptables -A FTP_ACCEPT -m state –state NEW -j LOG –log-level $LOG_LEVEL –log-prefix “fp=FTP:webmaster a=ACCEPT ” iptables -A FTP_ACCEPT -j ACCEPT iptables -N FTP_DENIED iptables -A FTP_DENIED -m limit –limit $LOG_LIMIT –limit-burst $LOG_LIMIT_BURST -j LOG – log-level $LOG_LEVEL –log-prefix “fp=FTP:attempt a=REJECT ” iptables -A FTP_DENIED -p tcp -j REJECT –reject-with tcp-reset for i in $FTP_IP; do iptables -A INPUT -i eth0 -p tcp -s $i –dport 21 -j FTP_ACCEPT done iptables -A INPUT -i eth0 -p tcp –dport 21 -m state –state NEW -j FTP_DENIED Bước 10: lọc TCP vào iptables -N TCP_INCOMING iptables -A TCP_INCOMING -p tcp –dport 80 -j ACCEPT iptables -A TCP_INCOMING -p tcp -j REJECT_PORTSCAN iptables -A INPUT -i eth0 -p tcp -j TCP_INCOMING Bước 11: lọc UDP vào và chặn ngập lụt UDP iptables -N CHECK_UDPFLOOD iptables -A CHECK_UDPFLOOD -m limit –limit $UDP_LIMIT –limit-burst $UDP_LIMIT_BURST -j RETURN iptables -A CHECK_UDPFLOOD -m limit –limit $LOG_LIMIT –limit-burst $LOG_LIMIT_BURST -j LOG –log-level $LOG_LEVEL –log-prefix “fp=UDPFLOOD:warning a=DROP ” iptables -A CHECK_UDPFLOOD -j DROP iptables -A INPUT -i eth0 -p udp -j CHECK_UDPFLOOD iptables -N UDP_INCOMING iptables -A UDP_INCOMING -p udp –dport 53 -j ACCEPT iptables -A UDP_INCOMING -p udp -j REJECT_PORTSCAN iptables -A INPUT -i eth0 -p udp -j UDP_INCOMING Để hạn chế khả năng bị DoS và tăng cường tốc độ cho máy chủ phục vụ web, bạn có thể dùng cách tải cân bằng (load-balacing) như sau: Cách 1: chạy nhiều máy chủ phục vụ web trên các địa chỉ IP Internet khác nhau. Ví dụ, ngoài máy chủ phục vụ web hiện tại 1.2.3.4, bạn có thể đầu tư thêm các máy chủ phục vụ web mới 1.2.3.2, 1.2.3.3, 1.2.3.4, 1.2.3.5. Điểm yếu của cách này là tốn nhiều địa chỉ IP Internet. Cách 2: đặt các máy chủ phục vụ web trong một mạng DMZ. Cách này tiết kiệm được nhiều địa chỉ IP nhưng bù lại bạn gateway Iptables 1.2.3.4 – 192.168.0.254 có thể load nặng hơn trước và yêu cầu bạn đầu tư tiền cho đường truyền mạng từ gateway ra Internet. Bạn dùng DNAT trên gateway 1.2.3.4 để chuyển tiếp các gói dữ liệu từ client đến một trong các máy chủ phục vụ web trong mạng DMZ hoặc mạng LAN như sau: # iptables -t nat -A PREROUTING -i eth0 -p tcp –dport 80 -j DNAT –to-destination 192.168.0.1-192.168.0.4