Security

Use firewall software like PF to protect your desktop systems

PF is the default firewall software for OpenBSD, and is an excellent example of a powerful, flexible firewall system. Something like it should be used to protect your desktop computer, and a minimal configuration example can help you get started.

Choosing an operating system with care can ensure a certain amount of security right away. At one end of the spectrum we find Microsoft Windows, which installs by default with a myriad of often unnecessary services turned on by default, a largely ineffective privilege separation model, and a vendor attitude toward security patching that could reasonably be described as "lackluster". At the other end, we find OpenBSD, whose core developers obsessively perform code security reviews, and whose base install comes with pretty much nothing turned on that could be used to access the computer remotely.

Once you have selected an OS, based on whatever criteria you decide are most important, measures can be taken to mitigate some of the problems that might come in a default install. For instances, turning off services in MS Windows is an important step toward reducing the security weaknesses normally found in the operating system. A number of other measures are important for any desktop deployment.

Even if all but the most critical services are shut down, there is always the possibility that one of the remaining services will be vulnerable, or that some bug in the system may allow a supposedly deactivated service to be exploitable anyway -- or, in the case of an OS whose updates can change basic configuration settings without the user's knowledge, as often happens with MS Windows -- an intentional "feature" of the system management model might allow previously deactivated services to be turned on again.

Firewalls can help reduce your exposure to remote exploits of vulnerabilities in your system's services. Some OSs have a firewall installed by default, and some of these firewalls are better than others. In some, that firewall software might be active by default, and in others it may be inactive. Configuration may be adequate to your needs, or it may not. In some cases, the default firewall software may not be the best choice available, and it may even be subject to the same potential for having its configuration silently and unexpectedly changed by system updates. These are all concerns that should be investigated by the conscientious user, and addressed with care.

Open source Unix-like systems tend to come with very well-regarded firewall tools, in terms of the fine-grained control they can provide and their strength and effectiveness. The Linux kernel offers iptables; BSD Unix systems offer options such as ipfilter. One of the most highly regarded suites of firewall software is the OpenBSD project's PF, which has been ported to every major BSD Unix system available. There is even a Microsoft Windows firewall application that claims to be based on PF source code called Core Force, though it must by necessity be heavily modified to run outside of a BSD Unix environment.

While PF does not by default offer the kind of point-and-click interface that MS Windows users tend to prefer, its flexibility and capability is far beyond what is offered by the Windows Firewall and other MS Windows firewall applications like ZoneAlarm. Amongst firewall software options that compare more directly to PF, it is considered one of the easiest to configure and maintain.

A minimal ruleset for PF on a desktop system can be set up in a handful of lines in a configuration file. On current OpenBSD, NetBSD, and FreeBSD systems, that configuration file is /etc/pf.conf. Such a ruleset might look like this:

tcp_services = "{ ssh }"

block all

pass in proto tcp to any port $tcp_services

pass from lo0 to lo0 keep state

pass out all keep state

Each of these lines serves an important purpose:

  • tcp_services = "{ ssh }": This is what is called a "macro" in PF parlance. PF macros serve much the same purpose as variables in many programming languages, in that you can use a single term to stand in for a varying value or a more complex value that would take a while to type over and over again. In this example, the SSH protocol has been assigned to the tcp_services command; if you have other services you need to work with in a similar manner, they can be added to that list, the PF shortcut terms for various protocols being separated by spaces.
  • block all: This is the first actual firewall rule in this ruleset. Because PF evaluates from top to bottom, each rule takes precedence over previous rules, so that earlier rules are treated as "defaults" and later rules as exceptions to those defaults. Taking a "least privilege" approach to security is usually a good idea, so we block all traffic by default and use more specific rules later in the ruleset to identify specific cases where we want to allow network traffic through.
  • pass in proto tcp to any port $tcp_services: This is the rule that makes use of the tcp_services macro. Because many Unix-like desktop systems are configured with an SSH server so that they can be securely accessed remotely from within the same network, for administrative and troubleshooting purposes, this rule allows any SSH traffic into the system. This assumes that you have some kind of external protection, such as a firewall for the entire network so that random security crackers on the Internet cannot directly access the desktop, and that you have your SSH service configured securely on the system as well; otherwise, you may want to use a more restrictive rule for the SSH protocol.
  • pass from lo0 to lo0 keep state: This rule allows the desktop system to communicate with itself via the localhost interface, which is important for a lot of common system functionality.
  • pass out all keep state: This rule has two important parts. The first is pass out all, which ensures it can send out whatever network traffic it needs to send. This can be dangerous on systems that might become infected by malware that then tries to contact the outside world to work mischief. On a firewalled BSD Unix desktop system in a network with good perimeter defense, operated by a tech-savvy user, this risk is so minimal as to be nearly nonexistent; on an MS Windows system, it is much more substantial, regardless of other conditions. Regardless of the OS, however, the risk does still exist.The second part of the rule, keep state, ensures stateful operation of network connections. This means that when the local system attempts to communicate with a remote system, and a connection is established, return communications from the remote system will be able to get through -- without affecting whether other remote systems will be able to establish unsolicited connections. In the most recent versions of PF, keep state is default behavior for pass rules, but including the keep state instruction should not cause any problems.

PF may be activated and this ruleset loaded in a single command:

pfctl -ef /etc/pf.conf

Further action may need to be taken to ensure that PF will run every time the system is booted, however. On FreeBSD, for instance, PF is not enabled by default. To ensure that it will start on system startup, and pick up your ruleset, add these lines to the /etc/rc.conf file:

pf_enable="YES"

pflog_enable="YES"

If PF is not already running, the above pfctl command on a default FreeBSD install needs to be preceded by loading the PF kernel module with the kldload command:

kldload pf

As already stated, this PF ruleset is minimal. Its simplicity makes it easy to understand, and easy to employ and extend. It may be sufficient for some needs, but improving on it for your particular needs is always a good idea. Even unchanged, however, this ruleset is a tremendous improvement over no firewall at all.

About

Chad Perrin is an IT consultant, developer, and freelance professional writer. He holds both Microsoft and CompTIA certifications and is a graduate of two IT industry trade schools.

20 comments
rjkirk
rjkirk

pfSense is a stripped down version of FreeBSD, to be used in either embedded or server-based firewalls. It offers a Web-based interface and outstanding documentation in the form of a widely-available book. 2.0 is almost out and it looks to be fantastic, with point-and-click OpenVPN configuration. I'm not affiliated with the project, except that I use it and consider it to be excellent.

Sterling chip Camden
Sterling chip Camden

I just noticed that after setting up PF the way you outlined above, my samba drives won't mount. mount_smbfs: can't get server address: syserr = Operation timed out Any advice?

Sterling chip Camden
Sterling chip Camden

When I'm at my home office, the entire network is behind a firewall device. But when I go out of town it would make sense to have a software firewall in place. This one looks good, and since it comes with your recommendation I'll definitely consider it.

apotheon
apotheon

Thanks for providing more information. I'm actually planning a review of the second edition of The Book of PF for publication here at TechRepublic. edit: By the way, there's an "edit" button so you can alter mistakes in your posts in cases like your incorrect link.

theidocles
theidocles

Who would have thought that a web site would automatically include the trailing ';' as part of a generated link? The correct URL for the Hansteen book is: http://nostarch.com/pf2.htm

apotheon
apotheon

The simplest modification from what I provided in the article is to simply add smb to the macro: tcp_services = "{ smb ssh }"

pgit
pgit

If the service is listed in /etc/services you can allow (pass) by name, iclude smb and nmb, eg: tcp_pass = "{ 80 ssh smb nmb ntp smtp 110}" You can always allow by port #, samba using 137, 138 and 139. You can specify a range with a ":" tcp_pass = "{ 80 ssh smb smtp 110 137:139}" I'm just learning this myself (sorta 'again') and tho I haven't done it, you can define a macro, eg use names in /etc/services (which defines ports) then add as argument to tcp_services. Like with any firewall a service obviously needs access to it's ports. I agree, pf is a lot more comprehensive to deal with than iptables. I just haven't dealt with any BSD deployments in the 'real world.' I'm hoping to soon make that "yet..."

Neon Samurai
Neon Samurai

I run the firewall on all internal nodes that I can in addition to perimeter points. A node on the inside is in a far better attack position than an outsider. Additionally, you can cut down on the network noise not relevant to the node.

pgit
pgit

Do you define "smb" someh9ow to the macro so you can use it by name? I thought you could only name something that is 'resolved' in /etc/services. My red hat based systems don't have any mention of smb, just the two daemons underneath it. Like I said in my previous I vaguely recall something about defining your own macro within pf itself, associating port(s) with name, absent mention is the services file. Probably wrong about that...

Sterling chip Camden
Sterling chip Camden

... but today I wanted to play the clueless jerk who thinks that RTFM stands for Relay To Forum Members. Thanks, apotheon and pgit!

Sterling chip Camden
Sterling chip Camden

I was planning to keep it enabled all the time. I only meant that I really need the extra protection when I'm roaming outside my perimeter.

apotheon
apotheon

Since I'm not doing anything with SMB right now, I do not really have any opportunity to experiment with it and see if I can narrow it down. People in the #pf channel on freenode seemed to confirm my understanding that protocol/service name definitions for use in pf.conf macros come from the /etc/services file, but if "smb" is working in a macro within Sterling's pf.conf file and is not defined in his /etc/services file, something else must be going on.

pgit
pgit

When I get the chance, I have a HD with freeBSD I throw in a test unit to experiment. I'm barely a newbie when it comes to BSD in the first place. But most of what I have done with it is look into pf. If you two can figure out how "smb" is defined for purposes of a pf macro it'd shed a lot of light on this. I hope it's something as simple as a section of pf.conf. (don't have access to mine atm)

apotheon
apotheon

My understanding is that protocol names are as listed in the /etc/services file; otherwise, services must be identified in macros by port. It is possible there is some other place where protocol names might also be defined, as in the case of Sterling's use of the smb protocol name, if that is actually working -- but if so, I am not aware of it. Maybe I can get Sterling to share his pf.conf with me so I can get a better picture of what's going on, and sort out why things are (or are not) working.

Sterling chip Camden
Sterling chip Camden

... that apotheon and I are both on FreeBSD. YMMV if you're on a different system, and I don't know enough to say by how much.

pgit
pgit

So the macro definitions must be build into pf then. I'll look the matter up when I get the time. But it goes back to my vague feeling there's some way to define your own. I see where you can define them, after RTFM-ing on "pf defining macros" on the intarwebs, but I still don't see a list of pre-defined ones... does pf actually consult the services at all? Or was that just a guideline for loose nuts like me?

Neon Samurai
Neon Samurai

One needs the firewall inside the office but one *really* needs the firewall outside the office. :D