Quản Trị  Hệ Điều Hành Linux - Unix
 
Thiết lập tường lửa Iptables cho Linux - Phần 2
11:48 | 10/04/2010
Phần II: Lập cấu hình Iptables cho máy chủ phục vụ Web

Phần này mình 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' bạn tự làm nha.

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. Bạn 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=0x08, 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:admin a=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

1. Trường hợp:
Firewall đơn giản cho một máy đơn.

2. Nhu cầu:
Bảo vệ máy đơn không bị rà và truy cập trong khi kết nối vào Internet. Máy đơn này không cung cấp dịch vụ cho những máy bên ngoài truy cập vào.

3. Phương pháp kết nối:
Modem, xDSL, Cable.

Đòi hỏi tối thiểu:
Đã hoàn tất thành công quy trình kết nối vào Internet (xuyên qua modem, xDSL, cable....) và có thể duyệt Internet hoàn chỉnh.

4. Mô hình:



- nếu là modem, ppp0 là external interface.
- nếu là xDSL, có hai trường hợp: ppp0 là external interface (nếu ISP ứng dụng PPPOE) hoặc eth0 là external interface (nếu ISP dùng DHCPD để assign IP cho user).
- nếu là cable, eth0 là external interface, IP address thường được phân bố qua DHCP.

5. Nhóm luật:
1.    IF=`/sbin/route | grep -i 'default' | awk '{print$8}'`
2.    IP=`/sbin/ifconfig $IF |  grep "inet addr" | awk -F":" '{print$2}' | awk '{print $1}'`
3.    IPT="/usr/local/sbin/iptables"
4.
5.    $IPT -F
6.    $IPT -P INPUT DROP
7.    $IPT -P OUTPUT DROP
8.    $IPT -P FORWARD DROP
9.
10.    $IPT -A OUTPUT -o $IF -s $IP -j ACCEPT
11.    $IPT -A INPUT -i $IF -d $IP -m state --state ESTABLISHED,RELATED -j ACCEPT


6. Phân tích:
- Dòng 1: Ấn định giá trị của biến IF bằng chuỗi lệnh ngầm, chuỗi lệnh này xác định network interface nào được gán với default gateway. Khi IF này ứng động và được phân bố một địa chỉ IP, nó cũng chính là default gateway ra vào của các packets trong quá trình truy cập Internet.

- Dòng 2: Ấn định giá trị của biến IP bằng chuỗi lệnh ngầm. Giá trị này được hiện hữu khi interface ở trên ứng động và kết nối vào dịch vụ cung cấp Internet. Đây là một chuỗi lệnh dùng để "tách" lấy giá trị IP hiện có trên IF. Nó tiện dụng vì bạn không cần phải điều chỉnh firewall script này mỗi khi IP address thay đổi.

- Dòng 3: Ấn định giá trị của biến IPT chỉ cho vị trí chứa iptables binary. Dùng cách này có hai điểm tiện là không phải gõ trọn bộ đường dẫn đến nơi chứa iptables và nếu nơi chứa iptables thay đổi vì lý do nào đó thì chỉ cần thay đổi ở biến này.

- Dòng 4: Dòng trống có chủ ý cho dễ nhìn.

- Dòng 5: Lệnh iptables với thông số -F có tác dụng xoá dội các chains còn vương vãi đâu đó (nếu có) khi firewall script này khởi tác. Đây là một lệnh thuộc dạng "house-keeping" (bảo trì) để gìn giữ tính trung thực và chính xác của các "rules" do iptables tạo ra. -F (flush) là một bước nên thực hiện vì mỗi lượt firewall script này được chạy, những rules cần thiết sẽ được ứng dụng và những rules không cần dùng (và còn vương vãi trên memory) sẽ bị loại bỏ.

- Dòng 6-7-8: Ba dòng trông đơn giản này kỳ thật đóng vai trò tối quan trọng. Tác dụng của mục tiêu DROP ở đây với thông số -P dùng để thiết lập chế độ (policy) cản mọi lưu thông trước khi cho phép loại lưu thông cụ thể nào đó được ra hoặc vào. DROP Policy là phương cách ngăn chặn vững nhất bởi vì những gì không cho phép sẽ bị cản. Chỉ có những gì được cho phép một cách cụ thể thì mới được đi qua. Hay nói một cách khác, khi một packet đi vào (hoặc đi ra) mà không có rule nào thích ứng cụ thể cho tính chất của packet này thì nó sẽ bị cản (DROP) theo chế độ chung của firewall.

Diễn dịch luật này thành ngôn ngữ bình thường như sau: theo chế độ mặc định (-P), các chains INPUT, OUTPUT và FORWARD hoàn toàn từ chối (DROP) mọi lưu thông.

- Dòng 9: Dòng trống có chủ ý cho dễ nhìn.

- Dòng 10: Đây là dòng xác định OUTPUT rule cho mọi packet đi ra từ IP và IF (đã xác định ở dòng 1 và 2). Rule này cho phép mọi packet, mọi loại giao thức (protocol) đi từ IP xuyên qua IF được phép đi ra ngoài. Với iptables, nếu bạn không xác định cụ thể loại giao thức (-p) trong một rule thì nó mang giá trị ngầm là mọi giao thức. Đây là một rule rất thư giãn vì nó hoàn toàn không giới hạn cho những packet đi ra, miễn sao nó đi ra từ IP và xuyên qua IF đã định. Đối với người dùng cá nhân, rule này rất thích hợp vì bạn không muốn tự hạn chế đường ra (ngoại trừ bạn có dụng ý bảo mật khác).

Diễn dịch luật này thành ngôn ngữ bình thường như sau: mọi packets  từ IP hiện dụng (-s $IP) xuyên qua interface eth0 (-o $IF) đi ra ngoài thì được chấp nhận (-j ACCEPT).

- Dòng 11: Đây là dòng xác định INPUT rule cho mọi packet đi đến IP và IF (đã xác định ở dòng 1 và 2). Rule này chỉ khác OUTPUT rule ở thông số và giá trị thông số -m state --state ESTABLISHED,RELATED. Điểm tối quan trọng cũng nằm ở đây. Nếu rule trên không có thông số và giá trị của thông số -m state thì firewall này hoàn toàn vô dụng bởi vì nó cho phép bất cứ giao thức nào, ở tình trạng nào cũng có thể lưu thông. Với -m state, packets đi vào sẽ được kiểm duyệt tình trạng của packets thoả mãn điều kiện ESTABLISHED hoặc RELATED. Cũng nên đào sâu vài điểm về tình trạng ESTABLISHEDRELATED ở đây:

- Một packet ở tình trạng ESTABLISHED có nghĩa nó thuộc một xuất truy cập (connection) đã hình thành và xuất truy cập này đã có diễn tiến trao đổi các packet từ hai phía "gởi và nhận". Với các luật ở dòng 10 và 11, chúng ta dễ thấy chỉ có packet từ firewall đi ra mới có thể ở tình trạng NEW để khởi tạo một xuất truy cập. Hay nói một cách khác, firewall của bạn "hỏi" thì đối tượng nào đó từ Internet mới "trả lời". Packet ở tình trạng ESTABLISHED có nghĩa là nó đã thông qua giai đoạn "hỏi / trả lời" một cách hợp thức. Điều này cũng có nghĩa, packets từ bên ngoài đi đến $IP xuyên qua $IF sẽ không được tiếp nhận ở tình trạng NEWINVALID cho nên các packets nào "hỏi" (NEW) hoặc "chen ngang" (INVALID) từ bên ngoài đến firewall sẽ bị chặn (tham khảo thêm tài liệu căn bản về iptables cho 4 states được sử dụng).

- Packet ở tình trạng RELATED không thấy nhiều như packet ở tình trạng ESTABLISHED bởi vì RELATED packet chỉ xuất hiện khi một xuất truy cập mới cần được thiết lập dựa trên tình trạng một xuất truy cập đang có đã được thiết lập một cách hợp pháp. Loại packet này có thể thấy ở giao thức FTP sau khi phân đoạn kết nối và xác minh người dùng (authentication) trên cổng 21 đã hoàn thành và cần thiết lập cổng dữ liệu 20 để chuyển tải dữ liệu. Ở đây, vì giao thức qua cổng 21 ở dạng ESTABLISHED cho nên cổng 20 được phép thiết lập thêm và phân đoạn này tạo ra packet thuộc dạng RELATED. Packet ở tình trạng RELATED cũng thường thấy ở các ICMP packets ở dạng trả lời (replies).

- -m state ở trên là một trong những tính năng thuộc dạng SPI -1- (stateful packet inspection - kiểm soát đa thể trạng) của iptables. Trước đây, với kernel 2.2.x series và ipchains (tiền thân của iptables), các packets được kiểm soát ở giới hạn loại packet và không thể kiểm soát ở biên độ tình trạng packet. Tính năng đa thể trạng này không những giúp bạn đơn giản hoá nhóm luật cho firewall của mình mà còn tạo nên một firewall linh động và vững vàng hơn rất nhiều. Nếu không dùng -m state ở đây, ít nhất bạn phải mở một loạt cổng nào đó (dãy 32000 - 64000 chẳng hạn) để các packets từ bên ngoài có thể đi vào để "trả lời" các requests bạn tạo ra. Đây là một phương thức có thể tạo những điểm yếu cho firewall, đó là chưa kể đến tính luộm thuộm khi phải cho phép chuỗi cổng cho mỗi loại giao thức (tcp / udp) và loại icmp ra vào cho thích hợp.

Diễn dịch luật này thành ngôn ngữ bình thường như sau: mọi packets  từ bên ngoài Internet đi vào IP hiện dụng (-s $IP) xuyên qua interface eth0 (-i $IF) vào trong máy ở chế độ ESTABLISHED,RELATED thì được chấp nhận (-j ACCEPT).

7. Tổng lượt dạng firewall trên:
Nhìn vào vài dòng luật của firewall trên, chắc chắn có người sẽ thắc mắc và sẽ hỏi chỉ có vậy thôi sao?.

Câu trả lời ngắn: chỉ có vậy nếu chỉ cần như vậy.

Câu trả lời dài: cho một máy đơn và người dùng được quyền gởi bất cứ yêu cầu truy cập trên bất cứ giao thức nào từ bên trong máy ra ngoài cũng như cản bất cứ yêu cầu truy cập trên mọi giao thức từ bên ngoài vào thì vài dòng luật như vậy là đủ. Như bạn biết, trong khi máy chạy trên Linux sẽ có một số dịch vụ đang lắng nghe (LISTEN). Những dịch vụ này chỉ phục vụ cho riêng bạn và bạn không muốn bất cứ ai từ Internet truy cập vào các dịch vụ này. Luật ở dòng 11 ấn định: các packet đi vào (INPUT) chỉ có thể ở dạng ESTABLISHED và RELATED cho nên một đòi hỏi truy cập mới (new request) từ Internet vào không thể được hình thành. Khi một packet như vậy đi vào firewall, firewall sẽ kiểm tra xem có luật INPUT nào thích hợp cho phép nó đi vào, nếu không firewall sẽ cản nó theo quy định của quy chế mặc định (-P) là DROP. Ở đây bạn có một luật INPUT duy nhất và luật này quy định rất cụ thể tình trạng packet được cho phép vào. Khi packet từ bên ngoài Internet vào, firewall sẽ kiểm tra packet này:
- nếu nó hoàn toàn mới và không hề hiện diện trong bản tình trạng (conntrack table) của netfilter -2- thì packet này bị cản.
- nếu nó đã hiện diện trong state table của netfilter thì nó được tiếp tục đi vào.

8. Mở rộng:
8.1. Vấn đề logging:
Với các luật firewall trên, khi xét kỹ, bạn sẽ thấy thiếu một yếu tố rất quan trọng đó là thông tin logging. Nếu bạn muốn biết có bao nhiêu trường hợp các packets "vi phạm" (bên ngoài các luật cho phép của firewall trên), bạn cần dùng target LOG. Vậy đưa vào các luật để thâu thập các thông tin vi phạm ở đâu? Bạn chỉ cần thêm vài dòng tiếp theo sau dòng 11 ở trên như sau:
12.    $IPT -A INPUT -i $IF -d $IP -m limit --limit 1/s -j LOG --log-level 5 --log-prefix "BAD_INPUT: "
13.    $IPT -A INPUT -i $IF -d $IP -j DROP
14.    $IPT -A OUTPUT -i $IF -d $IP -m limit --limit 1/s -j LOG --log-level 5 --log-prefix "BAD_OUTPUT: "
15.    $IPT -A OUTPUT -i $IF -d $IP -j DROP
16.    $IPT -A FORWARD -i $IF -d $IP -m limit --limit 1/s -j LOG --log-level 5 --log-prefix "BAD_FORWARD: "
17.    $IPT -A FORWARD -i $IF -d $IP -j DROP


- Các luật trên đôi khi còn được gọi là "clean-up rules", nói theo thuật ngữ chuyên môn của firewall. Lý do chúng được gọi là "clean-up rules" vì chúng đóng vai trò "dọn dẹp" cho các luật đứng trước chúng. Các luật ở dòng 12, 13, 14, 15 ,16 và 17 có chức năng tương tự nhau, chỉ khác ở một điểm là mỗi cặp 12-13, 14-15, 16-17 có tác dụng cho các chains (INPUT, OUTPUT và FORWARD) riêng biệt.

-  Diễn dịch luật ở dòng 12 thành ngôn ngữ bình thường như sau: mọi packets đi vào thuộc chain INPUT, xuyên qua interface $IF đến địa chỉ $IP sẽ được log với prefix là "BAD_INPUT" ở chế độ --log-level 5 và ở giới hạn là 1 giây.
- Kế tiếp, ở dòng 13: vào thuộc chain INPUT, xuyên qua interface $IF đến địa chỉ $IP sẽ bị cản (sau khi bị LOG ở trên).
- Dòng 14, 15, 16 và 17 tương tự như trên cho chain OUTPUT và FORWARD.

Vậy điểm cần nhấn mạnh ở đây là vị trí của các luật trong một nhóm luật. Nếu các luật ở dòng 12-17 nằm trên các luật ở dòng 10-11 thì chắc chắn firewall của bạn trở nên vô dụng vì không có bất cứ packets nào có thể đi vào và đi ra vì, hễ một packet nào đi vào và đi ra đều "trùng" với luật đã ấn định (và đã diễn dịch ở trên). Tuy nhiên, khi các luật ở dòng 12-17 nằm dưới các luật dòng 10-11 thì chúng trở thành ích lợi. Một packet đi vào theo trình tự các luật đặt sẵn trong firewall trên, chúng ta sẽ thấy:
- nếu packet đó đi vào để "trả lời" cho một đòi hỏi từ firewall khởi tạo trước thì nó được phép đi vào (áp đặt bởi luật dòng 11).
- nếu packet đó đi vào mà không thoả mãn luật ở dòng 11, nó tiếp tục "bị" xét duyệt bởi các luật đi theo sau. Ở đây, dòng 12 và 13 chắc chắn sẽ "tóm" được packet vi phạm và sẽ được xử lý theo ấn định cho các packet đi vào (thuộc chain INPUT).
- nếu không có các luật đưa ra ở dòng 12, 13, 14, 15, 16 và 17 thì các packet không thoả mãn được luật đã ấn định của firewall cũng sẽ bị cản bằng chế độ đưa ra ở dòng 6, 7, 8 nhưng cản một cách im lặng. Điểm khác biệt ở đây là luật cụ thể ở dòng 12, 13, 14, 15, 16 và 17 sẽ tạo ra log trong /var/log/messages (theo mặc định) cho những packet vi phạm và sẽ cản chúng một cách cụ thể.

8.2. Cản các lưu thông cụ thể
Đối với các lưu thông đi vào INPUT chain, luật ở dòng 11 đã khá vững vì không có gói tin nào từ bên ngoài có thể đi vào nếu như bạn không gởi "request" ra trước. Cho nên, chúng ta chỉ mở rộng ở OUTPUT chain ở đây.

8.2.1 Cản trọn bộ trước, cho phép cụ thể sau
Câu hỏi được đặt ra là các loại lưu thông cụ thể nào cần được cản? Vấn đề này phụ thuộc vào mức cẩn thận (hoặc paraniod)hoặc nhu cầu của từng người dùng. Với một cá nhân muốn truy cập bất cứ nơi đâu, bằng bất cứ giao thức nào thì dòng 10 thuộc phần 5 ở trên hoàn toàn đáp ứng nhu cầu này. Tuy nhiên, với một cá nhân chỉ cần duyệt web và chat bằng Yahoo Instance Messenger chẳng hạn thì giới hạn này có thể thu hẹp lại rất nhiều. Trong trường hợp này, dòng 10 thuộc phần 5 ở trên có thể được thay thế bởi một dòng như sau:

$IPT -A OUTPUT -o $IF -s $IP -p tcp -d any/0 -m multiport --dport 80,443,5050 -j ACCEPT
Dòng trên có thể được diễn dịch nôm na: các lưu thông đi đến bất cứ địa chỉ nào (-d any/0) bằng giao thức tcp (-p tcp đến cổng 80 (cổng 443 và cổng 5050) (--dport 80,443,5050) -3- thì được chấp nhận. Dòng trên không đề cập đến vấn đề "state" của các gói tin (-m state) như ở dòng 11 thuộc phần 5, điều này có nghĩa các lưu thông này có thể đi ra ngoài ở bất cứ state nào tùy thích. Tuy nhiên, nếu bạn paranoid hơn nữa thì chêm vào một đoạn -m state thì càng vững hơn, ví dụ:

$IPT -A OUTPUT -o $IF -s $IP -p tcp -d any/0 -m multiport --dport 80,443,5050 -m state state NEW,ESTABLISHED -j ACCEPT
Dòng trên tương tự như ví dụ trước nhưng chỉ định thêm là các gói tin ở tình trạng NEW và ESTABLISHED thì mới được đi ra ngoài; những gói tin ở dạng RELATED và INVALID sẽ bị cản. Lý do, giao thức http và giao thức dành cho YIM không cần đến tình trạng RELATED và các gói tin ở tình trạng INVALID thì càng nên không cho phép lưu thông. Tất nhiên nếu bạn muốn dùng POP3 và SMTP thì phải thêm giá trị 25 và 110 cho chuỗi --dport ở trên.

Nếu đã thực sự "paranoid" như vậy thì tại sao không xác lập thêm một luật cho giao thức UDP? Nếu bạn không có nhu cầu gì đặc biệt thì có lẽ cổng 53 cho DNS là cổng cần thiết nhất:
$IPT -A OUTPUT -o $IF -s $IP -p udp -d

8.2.2 Cho phép trọn bộ trước, cản các cổng cụ thể sau
Trường hợp người dùng muốn tự do truy cập bất cứ nơi đâu, bằng bất cứ giao thức nào nhưng không muốn máy của mình "tự động" truy cập đến các cổng "nguy hại" (ví dụ như máy vô tình bị nhiễm trojan và bị biến thành zombie -4- để tham gia trong các cuộc tấn công từ chối dịch vụ chẳng hạn). Trong trường hợp này, cách giản tiện nhất là thêm hai dòng phía trên dòng 10 thuộc phần 5:

$IPT -A OUTPUT -o $IF -s $IP -p tcp -d any/0 -m multiport --dport 54321,12345 -j DROP
$IPT -A OUTPUT -o $IF -s $IP -p udp -d any/0 -m multiport --dport 54321,12345 -j DROP
Hai dòng trên chỉ định các gói tin đi ra ngoài và đến các cổng trong chuỗi -5- ở trên sẽ bị cản (các cổng nêu ra ở đây chỉ là một ví dụ, không cụ thể áp đặt tính nguy hại của các cổng trên trên thực tế). Lý do chúng ta phải thiết lập hai dòng luật tách biệt vì mỗi dòng dành riêng cho mỗi giao thức và lý do hai dòng trên phải được đặt trước dòng thứ 10 vì những gói tin đi ra phải được kiểm tra trước khi có thể đi ra. Như đã đề cập ở phần 8.1, vị trí các luật là một yếu tố tối quan trọng, đây là yếu tố quyết định các luật của firewall hữu dụng hay vô dụng.


9. Thử nghiệm:
9.1 Thử nghiệm 1:
Giả sử bạn có một dịch vụ đang chạy trên máy (telnet chẳng hạn, hoặc bất cứ dịch vụ nào hiện có trên máy). Sau khi đã ứng động firewall trên, bạn thử nhờ một người bạn nào khác tìm cách truy cập vào dịch vụ telnet này. Tất nhiên bạn phải cung cấp địa chỉ IP cho người bạn ấy.
- người bạn ấy sẽ thử: telnet <địa_chỉ_IP_của_bạn> 23 --> việc này sẽ tạo SYN packet từ bên ngoài vào cổng 23 đã được cản (filtered port) vì firewall trên không hề cho phép bất cứ truy cập nào khởi tạo từ bên ngoài.
- bạn xem thử syslog: tail -f /var/log/message | grep '<địa_chỉ_IP_của_người_bạn>'
- bạn xem /proc/net/ip_conntrack: cat /proc/net/ip_conntrack | grep '<địa_chỉ_IP_của_người_bạn>'
- bạn theo dõi tcpdump: tcpdump tcp port 23

9.2 Thử nghiệm 2:
Giả sử bạn đã ứng dụng các luật "paranoid" ở phần 8.2.1, chỉ cho phép từ máy truy cập đến cổng 80, 443 và 5050 cho tcp và cổng 53 cho udp. Sau khi ứng động firewall trên, bạn thử:
- truy cập đến một website không dùng cổng 80 tiêu chuẩn mà dùng cổng khác như 8000, 8080 chẳng hạn, ví dụ: http://www.awebsite.com:8000.
- bạn xem thử syslog: tail -f /var/log/message | grep '<địa_chỉ_IP_của_website_bạn_truy_cập>'
- bạn xem /proc/net/ip_conntrack: cat /proc/net/ip_conntrack | grep '<địa_chỉ_IP_của_website_bạn_truy_cập>'
- bạn theo dõi tcpdump: tcpdump tcp port

Qua hai thử nghiệm trên, chắc chắn bạn sẽ tìm thấy rất nhiều thông tin mới lạ và đây chính là cánh cửa mở rộng cho những điều đằng sau một nhúm firewall script đơn giản như trên.

10. Kết luận:
iptables thật sự không phức tạp. Điều thật sự phức tạp là quá trình phân tích và xác định chức năng của một firewall cho một nhu cầu cụ thể nào đó. Trong quá trinh phân tích và xác định này, bạn sẽ phải đi sâu vào vấn đề khảo sát và thu thập những thông tin cần thiết để hoàn thành một nhóm luật bảo vệ máy của mình. Đây cũng chính là điểm lý thú và bổ ích trong suốt quá trình thiết lập bởi vì chắc chắn bạn sẽ không chỉ dừng lại ở phạm vi một firewall và firewall đó làm được gì. Bài viết này tôi chủ ý đào sâu vào tính năng "stateful" của iptables và bỏ qua những chi tiết thuộc kỹ năng tạo shell script, run level script... Tùy bạn chọn lựa cách điều chỉnh script theo ý mình và chỉnh init script (run level) tùy môi trường.

11. Bị chú:
-1- SPI: Stateful Packet Inspection hay dịch nôm na sang tiếng Việt là "kiểm soát đa thể trạng", một khái niệm được đưa ra vào những năm đầu của thập niên 90 và được ứng dụng rộng rãi cho các firewall "hiện đại". Tính "stateful" được khai triển dựa trên tính chất của giao thức TCP. Riêng với iptables, tính "stateful" này không những ứng dụng cho TCP mà còn cho UDP (được biết như một giao thức có tính stateless) và icmp. Dựa trên tính chất của từng loại giao thức, iptables / netfilter lưu trữ tình trạng diễn tiến của các packets trong bảng theo dõi (state table).

-2- netfilter thuộc kernel side, iptables thuộc user side. Xem thêm các thông tin này trên website http://www.iptables.org

-4- zombie: một bán thuật ngữ bảo mật ngầm chỉnh định cho các máy bị nhân nhượng và có thể được sai khiến từ một hoặc nhiều máy từ xa để thực hiện các ý định cụ thể nào đó.

-3,5- iptables cho phép 15 cổng trong chuỗi comma delimeter (,) cho giá trị --dport (destination port) và --sport (source port) nếu dùng match -m multiport. Dùng cách này hiệu năng hơn cách dùng từng dòng luật cho mỗi cổng cần cản hoặc cần cho phép.

Liệt kê nhóm luật "paranoid" cho phần 8.2.1:
1.    IF=`/sbin/route | grep -i 'default' | awk '{print$8}'`
2.    IP=`/sbin/ifconfig $IF |  grep "inet addr" | awk -F":" '{print$2}' | awk '{print $1}'`
3.    IPT="/usr/local/sbin/iptables"
4.    ISP_DNS="xxx.xxx.xxx.xxx"
5.    $IPT -F
6.    $IPT -P INPUT DROP
7.    $IPT -P OUTPUT DROP
8.    $IPT -P FORWARD DROP
9.    $IPT -A OUTPUT -o $IF -s $IP -p tcp -d any/0 -m multiport --dport 80,443,5050 -m state state NEW,ESTABLISHED -j ACCEPT
10.    $IPT -A OUTPUT -o $IF -s $IP -p udp -d $ISP_DNS --dport 53 -m state state NEW,ESTABLISHED -j ACCEPT
11.    $IPT -A INPUT -i $IF -d $IP -m state --state ESTABLISHED,RELATED -j ACCEPT
12.    $IPT -A INPUT -i $IF -d $IP -m limit --limit 1/s -j LOG --log-level 5 --log-prefix "BAD_INPUT: "
13.    $IPT -A INPUT -i $IF -d $IP -j DROP
14.    $IPT -A OUTPUT -i $IF -d $IP -m limit --limit 1/s -j LOG --log-level 5 --log-prefix "BAD_OUTPUT: "
15.    $IPT -A OUTPUT -i $IF -d $IP -j DROP
16.    $IPT -A FORWARD -i $IF -d $IP -m limit --limit 1/s -j LOG --log-level 5 --log-prefix "BAD_FORWARD: "
17.    $IPT -A FORWARD -i $IF -d $IP -j DROP

  Xem tiếp phần 3 >>
 
Ý kiến phản hồi và bình luận Góp ý kiến của bạn

Các tin mới nhất :
- Thiết lập 1 hệ thống High-availability - Loadbalancing và Reverse Proxy cho Web Server trên CentOS 6/RHEL Sử dụng HAProxy và Keepalived
- Đồng bộ hóa dữ liệu giữa hai Server Ubuntu 11.10 sử dụng Unison.
- Bảo vệ thư mục web với mod_auth_mysql trên Apache2
- Tích hợp MailScanner - ClamAV - SpamAssassin - SquirrelMail vào PostfixTrên Centos 5.7
- Cài đặt rsnapshot trên CentOS
- Xây dựng hệ thống NAS Cluster sử dụng OpenFiler
- Cài đặt Nginx trên Ubuntu 11.10
- Thiết lập hệ thống Active/active Samba CTDB Cluster sử dụng GFS & DRBD Trên Centos 5.7 X86_64
- Thiết lập máy chủ Ubuntu 11.10 và cài đặt ISPConfig 3 (Phần3)
- Thiết lập máy chủ Ubuntu 11.10 và cài đặt ISPConfig 3 (Phần2)
Các tin liên quan :
- Cài đặt lighttpd trên Linux
- Kiểm tra file, service và restart service khi cần thiết với Monit
- Tối ưu và tăng tốc PHP với XCache !
- Thiết lập Openvpn trên Server Linux
- Thiết lập tường lửa Iptables cho Linux - Phần 1
Bài nhiều người đọc cùng chuyên mục
Thiết lập 1 hệ thống High-availability - Loadbalancing và Reverse Proxy cho Web Server trên CentOS 6/RHEL Sử dụng HAProxy và Keepalived
 
Cài đặt Nginx trên server CentOS 6 x86_64 với PHP5 hỗ trợ qua PHP – FPM và MySQL.
 
Cấu hình ftp server với vsftpd
 
Quản lý đĩa trên linux dùng kỹ thuật LVM (Phần 1)
 
Cài Đặt Web Server (LAMP )Trên Centos 6 X86_64
 
Cài đặt và cấu hình Server Linux CentOS hoàn chỉnh (Phần 1)
 
Cài đặt công cụ giám sát web server apache
 
Trang chủ | Giới thiệu | Quảng cáo | Liên hệ
Giấy phép ICP số 199/GP-TTĐT. Bộ Thông tin và Truyền thông cấp.
Cơ quan quản lý  : Công Ty Cổ Phần Kênh Giải Pháp
Bản quyền © 2010-2011 Kenhgiaiphap.vn . Giữ toàn quyền.
Ghi rõ nguồn "Kenhgiaiphap.vn" khi phát hành lại thông tin từ website này.

return false; });