skip to content

PHP: Preventing X-PHP-Script Exposure of Variables

Not so long ago a patch was added to the PHP source code that, when mail is sent using the mail() function, has the effect of exposing both the script address on the server and the IP address of the remote user (the person submitting a contact form that sends email for example).

The logic behind this is clear. So many open source PHP applications have security holes allowing emails to be sent that it became necessary to find a way to identify the source. Before this patch it was not possible for the average user to do so, and certainly not for the recipient of spam sent using those techniques.

The problem is that, without much fanfare, many sites that are otherwise secure are having information about their technology and directory structure (the path to scripts in protected areas) and private IP addresses (the home of office IP address of the user) exposed every time a script is used that sends emails from the server.

A Simple Solution

Suggested solutions for those who don't want the X-PHP-Script mail headers to appear range from self-editing the patch to change the behaviour, to avoiding use of the PHP mail() function altogether. Not entirely useful.

Examining the patch contents shows a simpler solution. It seems it's relying on PHP $_SERVER variables to add a mail header in the following format to outgoing emails:

X-PHP-Script: <server_name><php_self> for [<forwarded_for>,]<remote-addr>

So what could be simpler than overwriting those variables before the mail() function is called, and then restoring them afterwards. If you already use a wrapper for sending mail then this is a once-off change. Otherwise, if you call the mail() function directory from your scripts, you'll have to modify each instance.

For our purposes it was sufficient to display just the homepage address (/) in place of the full path to the script (PHP_SELF) and to replace the users IP address (REMOTE_ADDR) with our own (SERVER_ADDR):

<?PHP // prevent user/script details being exposed in X-PHP-Script header $oldphpself = $_SERVER['PHP_SELF']; $oldremoteaddr = $_SERVER['REMOTE_ADDR']; $_SERVER['PHP_SELF'] = "/"; $_SERVER['REMOTE_ADDR'] = $_SERVER['SERVER_ADDR']; // send the email mail($to, $subject, $message[, $additional_headers[, $additional_parameters]]) // restore obfuscated server variables $_SERVER['PHP_SELF'] = $oldphpself; $_SERVER['REMOTE_ADDR'] = $oldremoteaddr; ?>

You can also disable the patch entirely by using unset() on one or more of the relevant $_SERVER variables.

You might also consider writing your own wrapper for the mail function that gives you the option of disabling X-PHP-Script for protected scripts, but allowing the default behaviour for public forms. That is beyond the scope of this article.

Comments and feedback are welcome as always through our Feedback link below.

References

< PHP


Send Feedback

Use this form to send a message to The Art of Web:


used only for us to reply, and to display your gravatar.

CAPTCHA refresh

<- copy the digits from the image into this box

press Esc or click outside this box to close

Load Feedback Form

User Comments and Notes

30 November, 2011

In my case the site was hosted in a cloud environment and even though I replaced the (REMOTE_ADDR) with the (SERVER_ADDR), the X-PHP-Script still additionally showed the users IP address (my own).

I got around this by placing the following code before the php mail function:

if(isset($_SERVER['HTTP_X_FORWARDED_FOR']) && !empty($_SERVER['HTTP_X_FORWARDED_FOR'])){
$oldremote_fwd_addr = $_SERVER['HTTP_X_FORWARDED_FOR'];
$_SERVER['HTTP_X_FORWARDED_FOR'] = $_SERVER['REMOTE_ADDR'];
}

and then after the mail result, I did the following:

if(isset($_SERVER['HTTP_X_FORWARDED_FOR']) && !empty($_SERVER['HTTP_X_FORWARDED_FOR'])){
$_SERVER['HTTP_X_FORWARDED_FOR'] = $oldremote_fwd_addr;
unset($oldremote_fwd_addr);
}

You may have other $_SERVER variables depending on your environment.

Hope this helps someone else!

2 September, 2010

Oh! Great! It works;
You can change <server_name> by this code:
$_SERVER['SERVER_NAME'] = "your server";

29 January, 2010

Perfect! Searched all over to find this info. Thank you.

top