Server Fault is a question and answer site for system and network administrators. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I'm trying to make a very secure iptables configuration. I had some problems with an old configuration. Specifically I used to block a lot more of ICMP and allow a few specific ICMP types, but this seemed to cause periodic DNS issues.

This one appears to work (mostly). I can traceroute the server just fine. I'm testing this all in a virtual machine first. It has to pass PCI Compliance.

*filter
:INPUT DROP [5:735]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type any -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 13 -j DROP
-A INPUT -p icmp -m icmp --icmp-type 14 -j DROP
-A INPUT -p udp -m udp --dport 33200:33500 -j REJECT --reject-with icmp-port-unreachable
-A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A OUTPUT -p icmp -m icmp --icmp-type any -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 25 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 53 -j ACCEPT
-A OUTPUT -p udp -m udp --dport 53 -j ACCEPT
-A OUTPUT -p udp -m udp --dport 33200:33500 -j ACCEPT
COMMIT

Is there any problems with the above configuration?

I'm using CentOS 5.6. Also what is the best way to prevent brute-force attacks on the SSH port? (I'll be changing ssh to a random port)

share|improve this question
up vote 1 down vote accepted

To prevent brute-force attacks SSH you will likely want rate limit connections. There are also programs like fail2ban which can be used to blacklist the IPs from which brute-force attempts are originating.

If you want a secure firewall, I would suggest you use a firewall build tool to build the firewall. I use Shorewall which has lots of documentation on how to build firewall rules for various cases. In your case I would consider starting with the one interface example and build from there.

Be careful blocking ICMP as some codes are essential for network operations. Shorewall will ensure you have the needed types enabled. You have options to enable or disable echo requests as required.

EDIT: There are some ICMP types you may not want to allow. However, you need should enable at least destination-unreachable(3), source-quench(4) and time-exceeded(11). For ping and traceroute you want echo-request(8) enabled, possibly outgoing only.

share|improve this answer
    
Actually one of the best ways I have found to limit brute force attacks is to use fail2ban. That also works for a number of other services as well. – Squidly Sep 22 '11 at 0:29
    
Shorewall seems a bit over my head at the moment. Would love to know which ICMP types are safe to block and which ones are not. For now I'm just blocking the timestamp ones for PCI. Would also like to see recommended configuration for rate limiting a port. – Luke Sep 22 '11 at 5:10

I realize this is extremely old. Just posting this in case someone stumbles across it in the future.

I've never understood why anyone would ever want to set the OUTPUT policy to DROP. From a security context it sounds good, but in practice it causes more headaches than anything else. As a result, an OUTPUT DROP policy doesn't make sense and creates a lot of unnecessary work. Here's my rational policy: If I don't want to initiate connections and send data outside of the server, then I simply don't run any programs that initiate unwanted connections and send data outside of the server! You also don't need that for PCI compliance. A default DROP policy for OUTPUT is much more likely to result in a broken firewall setup in various unexpected and surprising ways. So just don't do it.

The "best way" to prevent brute-force attacks against SSH is to not have SSH at all. That is, if you really want to lock down a system, require two (or more) people to be physically present at the machine to access it. SSH is convenient. The antithesis of security is convenience. If you want SSH to be enabled, you can do things like hide the SSH port (e.g. SPA or web knocking) or toss a solution like fail2ban as others have mentioned at it to introduce rate limiting. Also, configure sshd to disable password logins - that is, only allow SSH keys. And finally configure PAM to log and send e-mails whenever anyone successfully signs into the system regardless of source (SSH, console, etc).

Also, for anyone wandering into this and wondering "What firewall rules do I need to set up for PCI compliance?" The correct answer is: None! PCI compliance is a set of policies for storing and retrieving credit card information. It has no relevance to system level firewalls. You just have to ensure that all the people with access to the system are properly audited so that if something goes wrong there is an audit trail to follow (e.g. logging the user when they SSH to the box, logging the user when they make SQL queries against the database, etc). Any programs on the box that push data outside the box also strictly audit themselves. That's it - that's all PCI compliance is and ever was meant to be. Anything on top of that (firewall rules, VPN only access, etc) is icing on the cake.

Blocking ICMP timestamps is rather irrelevant. Reading what limited information I could find on the topic, they are related to bugs in time-based authentication protocols from...1999(!) that are detected by so-called "modern" security scanners (hahaha). This is 2016 (and even when the original post was made, it was still outdated), no one uses time-based authentication except for two-factor auth, but that's something completely unrelated to the issue at hand and 2FA solutions generally don't make network requests. A server should be kept in sync with reality anyway with NTP, so an attacker is already going to know what the server's timestamp is. While blocking such requests doesn't hurt anything that I'm aware of, doing so is absolutely irrelevant to PCI compliance.

So, to answer the original question, your firewall rules should look like:

*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp --syn --dport 80 -j ACCEPT
-A INPUT -p tcp --syn --dport 443 -j ACCEPT
-A INPUT -p tcp --syn --dport 22 -j ACCEPT
-A INPUT -p icmp --fragment -j DROP
-A INPUT -p icmp --icmp-type 3 -j ACCEPT
-A INPUT -p icmp --icmp-type 4 -j ACCEPT
-A INPUT -p icmp --icmp-type 8 -j ACCEPT
-A INPUT -p icmp --icmp-type 11 -j ACCEPT
COMMIT

If you want to get fancy, you could drop invalid port scanning packets early on. Those rules get messy-looking pretty fast and are unnecessary - do you really care if someone port scans you? Oh noes - a port scan! They're going to discover three open ports! I added --syn to only allow valid SYN packets through to the TCP rules. SSH might have some issues though (e.g. if you encounter frequently dropped SSH sessions, try removing the --syn option). If the connection becomes RELATED/ESTABLISHED, then the first rule allows subsequent packets through on the established connection. The -m options are implied with -p, so I dropped those. ICMP types 3 and 4 are essential/required, 8 for ping (optional), 11 for traceroute (optional). Fragmented ICMP packets are only ever part of a DoS attack. Of course, the OUTPUT policy is set to ACCEPT. The end result is the above. Other than the first rule, the rules and policies above look really nice, clean, simple, understandable, and organized - the way everything about a server configuration should be.

Don't forget about IPv6! You don't want to set up iptables and forget about ip6tables. For IPv6, the above rules should be:

*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp --syn --dport 80 -j ACCEPT
-A INPUT -p tcp --syn --dport 443 -j ACCEPT
-A INPUT -p tcp --syn --dport 22 -j ACCEPT
-A INPUT -p icmpv6 -j ACCEPT
COMMIT

IPv6 utilizes ICMP heavily, so blocking ICMPv6 traffic is currently considered bad practice. I've also not seen any particular firewall rulesets worth using for more strict ICMPv6 that don't look complicated.

I have personally tested both the IPv4 and IPv6 rulesets as-is in a production environment and they work as expected. Copy-pasta away!

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.