How to limit outbound SMTP mail sent from PHP

Damien Overeem picture Damien Overeem · Jun 20, 2013 · Viewed 8k times · Source

We have shared hosting servers which use PHP fastcgi (on IIS) for several clients (shared hosting). Regularly clients use old exploitable code which causes holes in their applications that eventually gets used by hackers to install malicious code. Most of the time this code is being used to send spam from our servers.

We have no control over our clients code, so patching the holes is quite impossible.

We would however like to block the clients sending spam once they send more then X email messages in Y amount of time.

The setup is fastcgi based, so there is little relation between php and the webserver. PHP sends its mail through SMTP on localhost. The mailserver allows relay of all localhost connections (obviously).

One thing that goes through my mind is setting an environment variable containing an identifier in the fastcgi environment and using php's prepend file option to add a header to all mail send by php's mailer. After that we could use that mail header to identify the spamming culprit.

The option above still would not take care of spam scripts using regular telnet (telnet localhost, HELO, MAIL FROM etc... ) when sending email.

My question to you: is the idea that i've mentioned the best and perhaps only option to deal with our issue? Or are there better solutions for this situation? And if so, please explain how you would deal with the issue.

Answer

ToxaBes picture ToxaBes · Jun 23, 2013

You can filter that on you MTA (message transfer agent). For example, allow no more than 50 emails in 1 hour for each user in Exim ( http://www.exim.org ) config file (/etc/exim/exim.conf):

begin acl

acl_check_not_smtp:
warn ratelimit = 0 / 1h / strict / $sender_address_local_part
log_message = Sender rate $sender_rate / $sender_rate_perio

acl_not_smtp = acl_not_smtp
begin acl
acl_not_smtp:
        deny message = Sender rate overlimit - $sender_rate / $sender_rate_period
        ratelimit = 50 / 1h / strict
        accept

And no matter how they try to send, via php mail() or other method.