Tuesday, December 13, 2011

Observations on SPF: Sender Policy Framework

Recently at work, I updated our SPF policy to something accurate.  Along the way, to understand the policy I was deploying and what the previous version actually meant, I had to understand the various rules and types involved.


What's the difference between Sender ID and SPF?

As far as I can tell, Sender ID (Microsoft; Wikipedia) supports more ways to identify the sender: not just the SMTP MAIL command (what I am calling the "From address" below), but also message headers.  They refer to the address that they decide to use as the Purported Responsible Address, PRA.  Other than that, the overall design seems practically equivalent to SPF.

What are the differences among 'a', 'ptr', and 'mx' in the SPF record?

These are all SPF "mechanisms", also called "types", to avoid confusion with the DNS records they're named after.

A bare "a" indicates that a forward (DNS A record) lookup for the hostname in the From address must be done.  If any resulting IP matches the IP of the sending machine, then the mail is permitted.  The form of "a:mail.example.com" means the same thing, but the A record to be looked up is "mail.example.com" instead, not the From address.

The "mx" type is similar, except that the mail exchanger (MX) record of the From address is looked up, with the resulting domain name used.  That is, a plain "mx" is equivalent to "a:mx.example.com" if the MX lookup returned mx.example.com.  The form "mx:example.net" is similar, but instead of using the From address domain, it is the MX record of example.net that is looked up in the first step.  I don't think the mx type has that much use in the real world; SPF is concerned with sending outbound email, while the MX records are for receiving inbound email.

The "ptr" type indicates that the sender's IP address should be looked up with a reverse (PTR) lookup.  (To protect against spoofing, the PTR hostname is then looked up forward (A), and if the original IP doesn't come back out, the "ptr" mechanism is ignored.)  Then, if the PTR hostname has the same suffix as the From address hostname, the mail is permitted.  Again, the From address hostname can be overridden by giving a hostname to the ptr record, as in "ptr:example.com".  This lets any machine with a reverse-address such as mail4.b.stl.example.com send mail (as *.example.com matches example.com).

Technically, when I said the mail is permitted, I mean "the mechanism matched"; since I didn't supply an action like "~a", the default is "+a", so the action taken because the mechanism matched is acceptance, more often called SPF Pass.  (This post just reflects how I think about it inside my head.)

You said "A record," which is IPv4.  This is the future—what about IPv6?

It turns out that SPF is defined intelligently; if the sender's connection is over IPv6, then all "A lookups" I mentioned above become AAAA lookups, and of course the PTR lookup also operates on the IPv6 specific domain.

An SPF policy can declare ANY unrelated domain to be a permitted sender?

Yes.  The designation happens in the SPF record, which is initially looked up through the From address.  Therefore, there's nothing that example.com can (legally) do to be specified as responsible for example.org's mail without cooperation, since they can't alter example.org's SPF record directly.

Can't spammers use SPF too?  They already do fancy DNS tricks for their websites.

Yes, and I've seen it in the wild (a spam message with SPF permitting it.)

Logically, then, SPF's role must be to authenticate the sender of a message.  Once the sender can be trusted (SPF accepts the message), the domain name can be used to look up its reputation.  In older times, a spammer could send mail claiming to be From example.com, trading on example.com's reputation, and there was no way to uncover the deception.  SPF should solve that last problem, but authentication alone doesn't guarantee non-spam email.

So what does your SPF record look like, sapphirepaw?

At work, we send out mail from one local server; from our hosted Exchange; and soon, from Amazon SES.  The policy is therefore a simple chain of rules:
v=spf1 a:notifier.example.com ptr:xchg.example.net include:amazonses.com -all
The "a" type specifies our outbound server; the ptr is specified by our Exchange hosting company; the include is specified by Amazon SES; and we forbid the rest.  For the road warrior, native Exchange, smtp+imap access, and OWA will all send via xchg.example.net, so we didn't need to make any special provisions there.

Names have been changed, except for Amazon SES, which is a public service with publicly available documentation.  There didn't seem to be much point in hiding that.

At home, sapphirepaw.org has just one server, so it's dead simple:
v=spf1 a ~all
I haven't gotten around to thoroughly testing it yet, so it still soft-fails, but that's how it is so far.  Both work and home records are published as TXT since the respective DNS managers don't support SPF types yet.


You can find more posts like this under the tip tag; or check explanation for longer, in-depth technical articles.  You can also follow me on twitter.

No comments: