php-secure-sendmail
Script for limiting no. of sent mail from PHP per domain
What is it good for
Imagine you run webserver with many virtual domains. But some bad customer writes a PHP script to
send thousands of email messages in a loop (maybe it's his intention, maybe only bug which makes
the loop never-ending, but that doesn't make a difference for us). Or customer has badly written
scripts with security bugs and some spammer exploits this to send a lot of spam through your server.
Features of php-secure-sendmail
- Mark every email sent from PHP in headers with originating virtualhost (X-Domain header) and info where to complain
- Optionally set envelope-sender (so that any bounces don't go to www-data mailbox, but to customer)
- Limit number of sent messages for every virtualhost
- You can set a default and specific limits for some virtualhosts
- You can set limit for 3 time periods - for example virtualhost can send max. 50 emails in 5 minutes, but not more than 100 emails in 30 minutes and 200 emails in one hour (this permits scripts which send more messages at a time)
- Detailed warning is print to apache default error.log when limit is exceeded (incl. time, virtualhost and which limit)
- Logs details (virtualhost, date+time, recipient) to MySQL database
- Automatic deleting of old records from database (garbage collection)
- No modification of apache/php required (just set sendmail_path to the script location)
Requirements
- python with mysql module (package python2.3-mysql on Debian)
- apache
- php
Installation
- Unpack php-secure-sendmail.zip to some common directory (/usr/local/ for example)
- Set permissions of php-secure-sendmail directory to 711 (so that apache user can't see list of files here)
- Set permissions of secure_sendmail.py to 755 (so that apache user can execute and also read it - a must for scripts to be run)
- Edit secure_sendmail_mod.py to return your database password (simple return "myPassword" is enough, but it is relatively easily read by bad customer)
- Run python secure_sendmail_mod.py as root - this will create compiled version secure_sendmail_mod.pyc which is harder to read
- Delete original secure_sendmail_mod.py (or move to location where apache can't read it)
- Set configuration parameters in secure_sendmail_conf.py (should be self-explanatory)
- For every virtualhost set this in the <Virtualhost> section of httpd.conf:
php_admin_value sendmail_path "/usr/local/php-secure-sendmail/secure_sendmail.py www.this_domain.com user1@this_domain.com" (The second parameter is optional)
So no php compilation is needed, nor any change of customer php scripts - using mail() function in php will run our script instead of system sendmail binary
- Before :) you set it for every virtualhost, test it on only one :)
Test if mail sent using mail() function gets delivered OK, if it contains headers added by our script, if the mail details are logged to MySQL and also test limits (set to low value like 3 for testing and watch for return value of mail() and warning in error.log)
For few days watch for exceeded limits and alter configuration if any of your domains needs higher limit - this is not for limiting normal usage, but detecting when usage is too high compared to normal, so limits must be set correctly)
Download
You can download it here - php-secure-sendmail.zip.
Sample output in error.log
[Sun Apr 16 06:28:36 2006] [secure-sendmail] domain www.domainX.net: exceeded limit for 1 minutes (10)
[Mon May 1 14:54:02 2006] [secure-sendmail] GC was run (probability: 0.001; 656 rows older than 168 hours deleted)