README.security =============== Author: Ronald F. Guilmette --------------------------------------------- Last edit: Tue Jan 29 16:19:55 PST 2002 --------------------------------------- The 1.9s version of Matt Wright's FormMail script was developed for the benefit of sites that already make use of various earlier and unsecure versions of FormMail, including the 1.9 version, which may still allow remote exploitation by spammers. Such sites may elect to use this version of the FormMail script AT THEIR OWN RISK, however if at all possible, I advise against doing so. I _believe_ that I have corrected all of the security problems that allow this script to be hijacked by remote spammers, but generally speaking, FormMail has a bad history os serious security problems and YOU WOULD ALMOST CERTAINLY BE BETTER OFF DEVELOPING YOUR OWN MAIL SCRIPT FROM SCRATCH. Still, I understand that for many sites lacking in programming talent, replacing an already-installed FormMail script with a more secure version of the same thing may be the only viable choice. Several changes were made to the FormMail script in version 1.9s in an attempt to clean up and remove all of the insecurities in the script that are known to the author at the time of this writing. Specifically, all of the former code that attempted to validate incoming HTTP requests based on the value of the HTTP_REFERER en- vironment variable (whose value is derived from the client-supplied HTTP Referer: header) has been removed. This code, in addition to being deeply flawed with respect to security, was utterly pointless anyway because the HTTP client can easily set the value given in the HTTP Referer: header to anything he wants. Thus, even if the code in the prior (1.9) version of the script which allowed a null HTTP_REFERER value to `pass' the check were removed, it would still have been the case that an attacker could get past the HTTP_REFERER test simply by supplying a value in the HTTP Referer: header that made the script happy. Such values would have been easy to find (or guess) in any case. So the useless check on HTTP_REFERER was simply removed from the script. The script now relies entirely on new (and more secure) code that checks that the `recipient' address(es) is/are in fact allowed recipient addresses for the locally-installed instance/version of this script. Formerly, the FormMail script checked an array called `@recipients' to see if a given recipient address was allowed by the person who installed FormMail. But the code that did that checking contained many obvious security loopholes. So that code has all been entirely rewritten and replaced in this version (1.9s) of FormMail. Now, in version 1.9s, we check each recipient address against the values given in two arrays that are supposed to be defined by the installer at install-time. These are the `@recipient_addresses' array and the `@recipient_domains' array. Their meaning and usage should be obvious. See the regular README file for more information about setting up these arrays are install-time. It is believed that the new recipient address checking code is secure, and that it will properly disallow all attempts to trick FormMail into sending e-mail to any e-mail address other than one which the installer of the script intended to be a FormMail e-mail recipient. (Note that as part of the rewrite of the recipient address checking code new checks were also included to insure that no client-supplied recipient e-mail will be allowed to contain either a percent-sign (%) character or an exclamation-point (!) character. Such characters, if allowed, would leave open a loophole via which a spammer might be able to trick the local FormMail/mailserver combination into sending e-mail messages to other domains, even if that would otherwise seem to be pro- hibited by the definitions of the two @recipient_* arrays.) In addition to the removal of the HTTP_REFERER code and the rewrite of the recipient address checking code, some other security related changes have also been implemented in this version of the script: 1) The `email' and `realname' CGI parameters now have carriage returns and linefeeds properly stripped out before these values are printed to the local mail server. (The lack of such stripping was formerly a big security loophole.) 2) The envelope sender address is now forced to the installer-supplied $mail_admin value (via the Sendmail -f option). This should help to insure that any undeliverable bounce messages that might be generated if and when the script attempts to send to some bogus address are re- turned to some known/fixed mailbox that an attacker cannot override. (Note however that it is still the installer's responsibility to set this to some e-mail address corresponding to some local mailbox that _IS_ in fact frequently and routinely monitored by some live human.) 3) All indications of the specific version number of the script have been entirely removed from all script-generated HTML messages. (There's no sense in giving attackers extra and potentially useful information.) 4) In preparation for the possibility that spammers may still be able to find some clever way of hijacking even this (secured?) version of FormMail, several new X- e-mail headers are now generated by the script and appended to the other e-mail header lines (To:, From:, Subject:) that are generated by the script: o A new "X-Generated-By: Matt Wright's FormMail.pl v1.9s" header will be attached to each generated e-mail message, thus indicating exactly what piece of software generated the e-mail message. o A new "X-Script-URL: <>" header will be attached to each generated message, where the <> part will be set to the full URL by which the script was invoked. This will make the job of tracking down the broken FormMail scripts a lot easier if this script should ever be compromised by spammers in the future. o A new "X-Originating-IP: [<>]" header will be attached to each generated message, where the <> part will be the dotted-quad representation of the IP address of the specific HTTP client that caused the script to be invoked. This additional information may be of some help in tracking down perpetrators, if and when this version of FormMail is ever cleverly hijacked in the future. (We _believe_ that we have made such hijacking impossible, but one can never prove the absence of yet more problems/bugs, so better safe than sorry.) (Note that the information contained in this new header may perhaps only be marginally useful... even if this version of FormMail is in fact later found to still be vulnerable to hijacking by outside spammers... because the IP address given in this header may perhaps only indicate the IP address of whatever anonymizing proxy the spammer used/abused as he was tricking FormMail into sending out his spam.) o If any one of the comma-separated substrings of the `recipient' CGI parameter is found to NOT match anything in @recipient_addresses or in @recipient_domains, then a security notice is mailed to the local $mail_admin. This should help a lot to catch spammers who may be trying to perform experiments on a given locally-installed copy of FormMail in preparation for an attempted spam run. 5) In addition to all of the other changes noted above (all of which are focused on preventing abuse of FormMail by outside spammers) the 1.9s-p2 version of FormMail also fixes all FormMail security holes relating to possible cross-site scripting attacks. (``Cross-side scripting is a generic name for an entire class of possible security exploits which (a) can potentially be used to either (a) execute various `server-side include' directives on the system hosting the CGI script or which (b) can potentially be used to ``trick'' end-user browsers into executing client-side scripts or client-side commands with more or different privledges than they would normailly be given when they come from an untrusted site.) Problems with possible cross-site scripting holes have all been closed now by insuring that each name and/or value in each CGI name=value parameter pair will have any embedded < or > characters they contain converted to their HTML equivalents, i.e, < and >. Also, all documents returned by FormMail now have their character set forced to "iso-8859-1". One other small cosmetic change has also been implemented in this version of FormMail, namely the addition of a -bm (be a mailer) option flag to the invocation of the local mail server. When the local mail server is in fact Sendmail, this flag isn't needed, because it is assumed by default. However I previously experienced some trouble with another ``mailer'' type CGI script when I tried to hook it up to Postfix (the mostly-compatible Sendmail re- placement) unless I included a -bm option in the invocation line. So just to make extra sure things will work right, I added the -bm option to the line that invokes the local mail server. It never hurts to have it there, and in some cases, it may perhaps help.