I have commented in the past on the generally low security level of Microsoft ASP.Net web applications which stems from the closed Microsoft monoculture and a product strategy that prioritizes ease of use over security and privacy by hiding features and functionality from the user.
In the course of a security audit/penetration test of a social networking Web site this week that was developed and deployed on Ubuntu, I was reminded yet again that we all have something to learn. Even Linux geeks.
A common Web 2.0 rich Web application system deployment involves a Web server running php and postfix for delivery of email notifications to Web site members. There are 4 key system requirements for such a deployment:
- A. Deploy as a null client, i.e as a machine that receives no mail from the network, and does not deliver any mail locally. This is a hugely important requirement to not turning your Web server into a launchpad for spammers.
- B. Rewrite the default Apache www-data@domain with something more meaningful like
email@example.com without changing PHP code. This is both a usability issue and a security issue, since it is a bad idea to advertise the fact that your Web site operations are clueless to the point of not knowing how to change default LAMP settings.
- C. Provide a human-readable From: in the header so that the users of your great Web 2.0 social media app will see real names instead of your domain. This is definitely a usability issue unrelated to security.
- D. Mask the email addresses of your users so that you don’t disclose personal information. This is a basic data security and privacy requirement.
Here is how you do it:
Configuring Postfix properly will enable you to have a mail server that does not receive mail from the network
and sends mail without the default www-data@domain in the Return-Path:
A. How to configure Postfix as a null client
See Configuring Postfix as a null client
2 myorigin = example.com
3 relayhost = example.com
4 inet_interfaces = loopback-only
5 local_transport = error:local delivery is disabled
8 Comment out the local delivery agent entry
Line 2: Send mail as “firstname.lastname@example.org” (instead of “email@example.com”),
so that nothing ever has a reason to send mail to “firstname.lastname@example.org”.
Line 3: Forward all mail to the mail server that is responsible for the “example.com” domain.
This prevents mail from getting stuck on the null client if it is turned off while some remote destination is unreachable.
Line 4: Do not accept mail from the network.
Lines 5-8: Disable local mail delivery. All mail goes to the mail server as specified in line 3.
B. How to set Return-Path in mail headers
Rewrite default Apache www-data@domain with something more meaningful like email@example.com
We use the Postfix canonical address mapping for local and non-local addresses. The mapping is used before mail is stored into the queue and replaces all strings found in the header using a simple, yet very powerful find and replace strategy.
Step by step example:
I’m assuming you’re logged into the command line on your Ubuntu box as a non privileged user with sudo privileges
If you don’t know what this means – ask someone to help you.
1) Create a file using your favorite text editor, call it ‘canonical’ (the name is not important) and put in the following:
Each line is a /find/replace/ string, so you can use the canonical for almost anything, for example to replace
names like site_manager with site.manager@corporate_email_domain.com
2) Convert it in db format suitable for Postfix
sudo postmap hash:/etc/postfix/canonical
3) Put the canonical definition into your /etc/postfix/main.cf file like this:
canonical_maps = hash:/etc/postfix/canonical
4) Reload the Postfix server
sudo postfix reload
C. Provide human-readable From:
D. Mask the real email address of the sender
Using PHP mail correctly will enable you to provide a human-readable From and mask the sender email address. In this little PHP code snippet, we assume that $from is a standard PHP object with a name attribute, $site is a standard PHP object with an email attribute and $to is a valid recipient email address
$f = $from->name.' <'.$site->email.'>'; $headers = 'From: '.$f."rn"; mail($to, $subject, $body, $headers);
This is the minimal code to get the job done. More than this and you may be getting into trouble and certainly working too hard.
Most PHP developers use a framework like Yii or CakePHP or Elgg (if you’re writing a social networking application) that stores site-wide definitions like site email and site domain name. Make sure that you have the right value for the $site object. For example, in Elgg, the Site email address is site entity meta data and is set via the Elgg Administrator interface and not stored in a standard settings.php configuration file.
So, make sure you have the right value for the site email, e.g. firstname.lastname@example.org or whatever else you need it to be, otherwise, you will be spending a few hours wondering why your code is not working.
Have fun and make sure you don’t forget that there are both users and attackers out there.