Internet Firewall Essentials
It seems as if everybody is worried about connecting their organizations to the Internet these days. There are widespread reports of hackers breaking into everything from banks to warehouses and gaining unauthorized access to critical systems. If you're leading an internal World Wide Web development project for your company, you've probably had to face your own security advocates who decry the end of pristine systems yet offer no assistance in researching or developing a mutually satisfactory solution.
Well, here's your help. This chapter of Network Computing's Interactive Network Design Manual will outline the critical elements for implementing an Internet firewall in your organization, hopefully in a way that allows you to choose the solutions that best suit your needs. The options range from the cheap to the not-so-cheap, from the visible to the invisible, and from difficult to easy.
As individual requirements will vary, we cannot readily endorse any one product or approach over another, yet they all offer benefits that you may want to use. In this new market, most products are only partially finished—yet are completely priced—so your choices will likely end up as budgetary decisions as much as functional ones.
What, Exactly, is a Firewall?
Almost by definition, a "firewall" provides a filter that incoming or outgoing packets must pass through. If the firewall does something beyond filtering, like checking against a restrictions list, that's great, but it's not necessarily the "definition" of a firewall's function.
Of course, most firewalls do perform some sort of "accept" or "reject" functionality, but that's strictly a matter of implementation. The simplest firewall could just be an Ethernet bridge that you keep powered off, only to be made available when the connection is needed. This would probably work for keeping intruders off of your network, but I doubt you'd enjoy the management interface much. Most firewall products offer much more in the way of actively filtering packets according to certain criteria that you establish.
These filtering firewall products can take many forms. They may be a replacement TCP/IP stack that you load on an existing system, or a software module that exclusively communicates with an existing stack. At the other end of the extreme, the product may be a completely independent operating system written explicitly with Internet security as the objective. There are also application-specific firewall products that only offer protection for certain types of Internet connectivity, such as SMTP or HTTP. There are also hardware-based products that typically fall into the router realm, allowing you to set filters for incoming and outgoing connections. Prices range from free (bundled with the stack or app) to tens of thousands of dollars.
All of these products can rightly be called "firewalls" because essentially they trap inbound or outbound packets, analyze them, and then either send them on their way or toss them out. Any one of these products may or may not suit your needs. Once you've got a handle on the issues, however, you should be able to do your own product elimination, simply by comparing functional specifications.
At the least, almost all firewall products offer IP address filtering. These filters work by examining the header of the IP packet and making pass/fail decisions based on the source and destination IP addresses. For clarification purposes, let's look at the figure above, which shows a simple two-segment network with a firewall separating them. One segment has a UNIX host, and the other has a PC client.
When the PC client tries to Telnet to the UNIX host, the Telnet client on the PC generates a TCP packet, and hands it to the local stack for delivery. In turn, the stack places the TCP packet inside of an IP packet, and then sends to the UNIX host via the route defined in the PC client's TCP/IP stack. In our case, the PC client is sending the IP packet to the firewall for delivery to the UNIX host.
Suppose that we have told the firewall that it is not to accept any packets destined for the UNIX host, as depicted in below. Then the firewall would reject the IP packet, perhaps bothering to tell the client or perhaps not. Since no IP traffic for that destination would get forwarded, only users on the same segment would be able to access the UNIX host.
Another scenario might be that the firewall has been configured so that it simply will not accept any packets from that PC in particular. Then other systems could connect to the UNIX host, but that specific PC could not.
This type of filtering is the most basic of all. By setting accept or reject filters per IP address, these types of products can provide very basic protection mechanisms for a simple LAN. If the systems are not allowed to communicate because of source or destination IP address filters, then the packets are simply rejected.
These types of filters are commonly used in smaller shops that need to control where users can or cannot go, but beyond that they're not extremely reliable. IP addresses can be spoofed, so using these filters by themselves are not enough to stop an intruder from getting into your network. However, it is a fundamental building block of good firewall design, and is a critical component of a complete defensive infrastructure.
If you do employ IP address filters, then make sure that you use IP addresses when you create your accept and reject tables, and don't use DNS host names, since DNS can be spoofed even more easily than IP addresses can be.
TCP/UDP Port Filtering
Using simple IP address comparison to allow or reject packets is a brute method of filtering. It doesn't allow for the possibility that multiple services may be running on the destination host, some of which we may want to allow users to access. For example, we may not want users to Telnet into the system, but we may want them to be able to access the SMTP/POP mail server that's running on it. To enable this level of control, we have to be able to set filters according to the TCP or UDP port numbers in conjunction with the IP address filters described earlier.
For example, the default Telnet configuration calls for the server to monitor TCP port 23 for incoming connections. Therefore, if we know that we do not want to allow any Telnet connections to our UNIX host from the PC, we can simply tell the firewall to reject any IP packets going to the UNIX host that have a TCP destination port number of 23. Since the PC's Telnet client would normally generate just such a request, the service would effectively be disabled for it, as depicted above.
It should be pointed out that this type of setup—where we are explicitly excluding a port—is generally a bad idea. If you need to protect a system, you're better off by rejecting everything, and only accepting the TCP or UDP packets that you know you want to let through. It may seem like more work, but it's less work in reality, and has the added benefit of keeping your systems from being easily compromised. In other words, of the two approaches—that which is not forbidden is allowed, and that which is not expressly allowed is forbidden—the latter one is safer.
If we wanted to reverse this example, perhaps using SMTP and POP, then we would add these services to the acceptable list for the UNIX host's destination address, and reject all other packets. Therefore, any connection request bound for the UNIX host which had TCP destination port addresses of 110 or 25 would be allowed to pass, but no other packets would, since they wouldn't meet this "allow" condition. This would include Telnet, thereby providing the "exclude" condition described above, only with less work (told you so).
By combining the IP addresses and TCP/UDP port numbers, you can develop some pretty reliable filters. For example, if your internal SMTP mail server only talks to your Internet Service Provider's (ISP's) mail server, then you could implement a firewall filter that only allowed incoming SMTP connections that came from the ISP's mail server, and are destined for your internal SMTP mail server. This will keep some of the hackers from being able to exploit any SENDMAIL weaknesses that you haven't plugged.
This level of control is generally where many of the pseudo-firewall products stop. By allowing you to set your filters so that no incoming traffic from the Internet can access any ports except the ones you want, it would seem to preserve your security to a satisfactory degree. However, this is just not the case.
Clients have TCP/UDP Ports, Too
Since TCP/IP is a peer-to-peer protocol, each node has a unique address. This philosophy carries up into the applications layer as well, meaning that applications and services also have addresses (or port numbers). Since it takes two to tango, both the client and the server must have unique port numbers on their individual systems in order for a TCP or UDP connection to be established. For example, the Telnet server listens for incoming connections on port 23. However, the Telnet client also has a port number. Without this, the client's IP stack would not know which application the packet was for.
Historically, almost all TCP/IP client applications use a randomly assigned port number above 1023 for their end of the connection. This is a legacy from TCP/IP's roots in the UNIX world. On UNIX systems, only the root account has access to ports below 1024, which are reserved for server services (like Telnet, FTP, etc.). In order to allow client applications to work, they must use port numbers above 1023.
For you to allow any sort of connection to work then, you must allow any packet with destination port numbers higher than 1023 to come into your network. If the response packets are not returned, the client will not be able to establish a connection.
In terms of Internet firewalls, this can cause some problems in design. If you are to block all incoming ports, then you have just kept all of your clients from being able to use Internet resources. The inbound packets that are the responses to their external connection requests will not survive the firewall's inbound filters.
You may think that it's okay to open up all ports above 1023. Not so. There are a lot of services that run on ports higher than 1023, such as X clients, and RPC-based services like NFS and NIS/YP. Most of the non-UNIX IP-specific products—like NetWare/IP for example—use port numbers that are above 1023 as well. This means that if you let any old packet that meets the above-1023 criteria into your network, then you're exposing those systems to attack, and none of them are particularly well known for their robust security mechanisms.
Build Bi-Directional Filters
One potential solution to this problem is to build bi-directional filters into your firewall. You may want to define the filters so that you only allow packets that are from well-known services into your network, and reject any packets that are not from specific applications. For example, if you know that your users will be accessing World Wide Web servers, then you could only allow packets that have a source port number of 80 into the network, as illustrated below.
Unfortunately, there are a couple of problems with this solution as well. First of all, you don't always know what port numbers the servers that you are trying to access are running on. Modern day servers such as HTTP and Gopher are completely configurable in this manner, allowing you to run them on any port that you want to. If you implement this type of filter, then your users will not be able to access those sites that do not use the "standard" port numbers that you expect them to.
Another security problem comes from the fact that there is no way for you to know for sure that the packets coming into your network from port 80 are indeed response packets from a World Wide Web server. Some hacker may have compiled their own network invasion tool that runs on port 80 on their machine, thereby making their insidious data look perfectly harmless, at least to your firewall anyway. If they can get into your network just by setting their application's source port manually, then they can do whatever they want with the vulnerable systems, and your firewall will be useless.
Check the ACK Bit
If you can't trust the source IP addresses, and you can't even trust the source port numbers, then it doesn't seem like you can do much in the way of protecting your network from intruders. However, there is one fool-proof mechanism that you can use reliably, although only with TCP.
TCP is a "reliable" protocol that supports error-correction and other robust capabilities. To achieve this reliability, every TCP connection begins with a handshaking sequence that establishes specific parameters of the connection. Also, every packet that gets sent must be responded to with an acknowledgment before another packet will get sent.
Rather than generate special-purpose ACK packets for every TCP packet, a special bit in the TCP header is used for just this purpose. Therefore, whenever a response packet is generated, the ACK bit gets set, and a marker is noted to indicate what packet the ACK is for. The very first packet in a negotiation is not acknowledging anything, and so it does not have the ACK bit set. However, every subsequent TCP packet in an exchange must have the ACK bit set for the connection to be maintained.
For example, if the PC opens a connection with a remote World Wide Web server, it generates a connection request packet that does not have the ACK bit set. When the server responds to this request, it sends a packet with the ACK bit set, and with the marker set to the number of bytes received from the client. The client then responds to this packet with its own response packet, which also has the ACK bit set and with its own marker also set to the number of bytes of data received from the server. The figure above illustrates this series of events visually.
By monitoring the ACK bit, you can limit the types of incoming data to only response packets. This means that a remote system cannot initiate a TCP connection at all, but can only respond to packets that have been sent to it.
Nor can an outsider manually set the ACK bit for their first packet, thereby blowing past your security. The receiving node will see that the packet is an acknowledgment for a packet that it sent (referenced by the marker) and will discard it, as it would not be able to recall any such packet ever being sent.
This one trick by itself can go a long way towards protecting your network from invasion. If you can configure your firewall so that it will only give entrance visas to TCP packets that have the ACK bit set, then you are guaranteeing that no packets that have not been explicitly requested will arrive on your internal network.
This mechanism is not a panacea however, and is not usable in several situations. For example, if you have an internal World Wide Web server or some other data that you wish to provide on a public basis, then you would have to open port 80 (or whatever ports were to be used) so that external requests for connections could come into your network. Also, monitoring TCP packets for the ACK bit doesn't help at all with UDP packets, as they don't have any ACK bit. Some TCP applications are designed so that they initiate some connections, and these applications cannot work across a firewall that does not allow incoming connections. One such program is FTP.
The Problem With FTP
Unlike most of the Internet services that use a single pair of port numbers for all communications, FTP uses two pairs of port numbers during connections. The first pair is used for the FTP "command channel" that provides a communications line for logging in and executing commands, while the other pair is used for the FTP "data channel" that is used for sending files or directory listings between the client and server.
During a normal FTP session, the client will send a TCP connection request to port 21 (the "command" channel) on the server, and then execute commands such as LOGIN, DIR, and the like. Once the user requests that data be sent, the FTP server uses its local port 20 (the "data" channel) to initiate a connection to the client's "data" port. This presents a spectacular problem. If the server is going to initiate a connection to the client for the data transfer, then it will send a packet that does not have the ACK bit set, meaning your firewall will reject it, and thus the file transfer will never get started, much less finished. Only an advanced firewall will recognize that the client does actually tell the external server which port to use, and thus the firewall will allow incoming connections for ports that it has seen the client tell the server to use.
There is a workaround for this scenario however. Many FTP clients and servers support the use of "passive mode" file transfers (named after the PASV command), which allow the client to initiate the file transfer connection. Rather than the server using port 20, when it receives the PASV command it allocates a port above 1023, and informs the client of its choice (via the command channel). The client then initiates the TCP connection to the port number provided, and the server then begins to transfer data. Not all clients or servers support the PASV command, so this won't work in all situations, although it is becoming much more common. Almost all Web browsers use PASV mode by default, and almost every FTP client worth looking at supports it as well.
UDP Port Filtering
As I said earlier, monitoring the ACK bit in incoming TCP packets is a very effective way to allow outbound TCP connections. However, UDP doesn't offer this type of capability, since it does not have any ACK functionality. UDP is designed for unreliable transmissions which do not require or benefit from negotiated connections. These types of services generally include broadcasts, routing protocols, and other "maintenance" packets that advertise services. Unfortunately, there are lots of other services that use UDP as well, including NFS, NTP, DNS, WINS, NetBIOS-over-TCP/IP, and NetWare/IP. These types of services can be corrupted pretty easily, or used as launching pads for additional attacks on your network.
One possible solution to this problem is to simply not allow any incoming UDP connections. To enable this functionality, you need to be able to configure your firewall so that it will forward UDP packets received from the internal interface, but will not forward UDP packets received from the external interface. While this will certainly prevent any incoming UDP connections, it will not always be feasible.
For example, DNS name resolution requests use UDP, so if you are providing your own DNS services, then you must allow at least some internal connection requests to pass through your firewall. Also, there are client applications like Archie and IRC which use UDP, and if you want to provide them to your users you will need to let the appropriate response packets into your network.
You'll need to provide for some sort of UDP connectivity, whether it is for end-user applications or for system level services like DNS. About the only thing that you can do is to limit these connections to somewhat "trusted" sites. For example, you may want to filter DNS so that only UDP packets between your internal DNS server and your ISP's DNS server are allowed to cross the wire. Likewise, you could filter Archie packets so that only the UDP packets from a specific Archie server were allowed into the network. Talk, being a relatively uncontrollable application, is not easily configurable for filtering, and would likely have to be cut off altogether.
There is a risk with allowing even well-known hosts to send packets into your network, however. If a hacker can spoof the IP address of the host that you have given clearance to, then they can take advantage of your internal system, albeit to a limited degree. A new breed of packet-filtering routers are becoming available that attempt to solve this problem by "remembering" outbound UDP packets. If an incoming UDP packet matches the destination address and port number of a recent outgoing UDP packet, then it is allowed in. If no recent packet can be found in memory, the firewall will reject the packet.
Again, the fundamental problem with this approach is that there is no way of knowing for sure that the outside host generating the packet is indeed the service that the internal client is expecting to communicate with. If a hacker were to spoof the IP address of your ISP's DNS server, then they could theoretically launch an attack from the UDP port associated with DNS. However, this particular weakness would exist anyway if you were filtering UDP packets so that only DNS queries and results from your ISP were allowed into the network. Your situation is neither improved nor degenerated by deploying these dynamic packet-filtering products.
Proxy and Bastion Servers
One solution to these problems has been to utilize proxy servers or bastion hosts. These systems run from simple application redirectors to complete fully-intelligent routers that act as application agents on behalf of your network.
At the low end of the scale, products such as the CERN HTTPD server can provide proxy connections to remote FTP, Gopher and HTTP servers on behalf of your internal clients, thereby preventing them from connecting to remote systems directly. This has the effect of making these specific connections somewhat secure, as you can trust your proxy server to a certain degree, and do not have to allow any incoming connections from outside sources.
At the high-end, complete security-centric products that offer communication replacement functions don't allow any direct connections at all, and force everything to be examined and filtered for suitability. For example, BorderWare's Firewall Server offers proxy functionality like the CERN offering, but also provide public and private DNS servers, secure mail servers, and a variety of other functions. Since these products have multiple adapters, they essentially act as intelligent routers, rewriting packets in memory on a per-connection basis, rather than simply forwarding packets between the external and internal interfaces. These types of products can be extremely expensive, but they are also your best bet if this level of security is required.
There are other issues and concerns that even the fully-functional bastion systems offer no value with. You still have to concern yourself with some of the essential puzzlers of Internet security.
For example, IP addresses can be spoofed, so that a sinister host appears to be a trusted host. This is often accomplished through the use of IP's source-routing option, which essentially tells the routers not use their normal routes for delivery of the packet, but to send it via the router identified in the packet's header. This lets a hacker use another system's IP address, and get the packets back, regardless of what routes are in between him and the destination. Some of the higher-end products allow you to disable or ignore the source routing bit, but not all of them.
Disabling source routing can be a good thing to do. For Internet connectivity, you generally have one path out of your network, and that's through the ISP. If you disable source routing, you'll just return the packets back through your normal routing channels. The ISP will have to deliver the packets to the destination as they see fit. As your response packets will not have source-routing headers (since you've turned it off), the responses will follow the Internet's general routing tables.
Also, you will need to find out what the firewall product you are considering does when it rejects a packet. Does it send an ICMP "host unreachable" message back to the originating system, or does it send an ICMP "host administratively unreachable" message, or does it not do anything at all? Each of these scenarios have different security implications, and may make a difference in your choice of product.
The ICMP "host administratively unreachable" message will tell a hacker that a firewall is specifically blocking a specific port, which may be more information that you want to give out. The ICMP "host unreachable" error can be interpreted literally by older systems, who will then stop trying to send any packets at all to that host, which may not be the desired effect, either. Sending nothing back at all will cause the originating system to continually try to establish the connection until the application or stack times out, which can be annoying to end users who have made a simple mistake.
Sending nothing back is probably the safest method of the three, since a hacker cannot tell whether or not a port is blocked or simply not in use, but only that no responses come back at all.