Secure Encrypted FormMail

Secure Encrypted FormMail, PHP and GPG based.

We are all familiar with the original FormMail script created back in 1995, but are you familiar with a secure formmail script?

And by secure I mean one that encrypts the data.

I sure wasn’t so one night while I was up late, waiting for my scheduled maintenance window to come around, I typed one up.

On common misconception that I see a lot of people do is put an https URL for their formmail action tag, and then think the form is secure.

Well, that doesn’t help a whole lot, it would secure the data back to the server, but then emailing it to you would not necessarily be secure, especially if your mail server is different than your web server, plus there will be a period of time where the form results are in plain text on the server.

What you need is not only a formmail that will use https, but that will also encrypt the data with GPG.

That said I bring you Secure Formmail:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
<?php                                         
//Doug Walker's Secure Formmail Copyright 2009 FreeGPG.org
//This script is provided with absolutely no guarantee or warrrenty
//This script is not assumed to be bug free or error free          
//Secure Formmail may not be 100% secure, and may not be secure enough or appropriate for your specific use
//We are not responsible for misencrypted or unencryptable messages or damages caused by use of this script
//You agree to limit any loss from the use of this script to $5, which you agree is a fair amount since the script is free
//This script was developed using GnuPG v1.4.5                                                                            
//This script is meant to be used in conjunction with SSL (https://)                                                      
 
//***** YOU MUST SET $referrers $recipients AND ENTER YOUR PUBLIC KEY*****
 
//Set valid referring URLs, seperate multiple approved referrers with a , no spaces
$referrers="domain.com,www.domain.com";                              
 
//Set valid recipient domains
$recipients=$referrers."emaildomain.com,us.emaildomain.com";
 
//include your publickey, by default it is in publickey.txt in the same directory as this script
//include the Begin and End lines and no extra spaces                                           
//You can get a public key from freegpg.org but are not required to use that public key         
//***Paste the your key starting with the BEGIN line right below <<<EOI                         
//***and with your END line right above EOI;                                                    
$publickey=<<<EOI                                                                               
-----BEGIN PGP PUBLIC KEY BLOCK-----                                                            
Version: GnuPG v1.4.5 (GNU/Linux)                                                               
 
qwerwqerwer
YOUR PUBLIC KEY HERE
qwerqwerwq                                                      
-----END PGP PUBLIC KEY BLOCK-----                              
EOI;                                                            
 
// Escape the key and message for added security
$publickey=escapeshellarg(trim($publickey));    
 
//Declare variables
$secure=1; //Set secure mode 0 = off 1 = on
define('GPG', '/usr/bin/gpg');  // The gpg binary
define('HOME', '/tmp');         // .gnupg will be created here
putenv('HOME=' . HOME); //Set the home environment            
$to_max_len=200;                                              
$ref = getenv("HTTP_REFERER");                                
$timestamp = date("m/d/y  H:i:s", time());                    
$ip = $REMOTE_ADDR;                                           
$msg="";                                                      
//set referrer                                                
if($_SERVER['HTTP_HOST']!="")                                 
  $referrer=$_SERVER['HTTP_HOST'];                            
else                                                          
  $referrer=$_SERVER['HTTPS_HOST'];                           
//end set referrer                                            
$recipient=$_POST['recipient'];                               
 
//Begin the message with the referring URL, date/time stamp, and remote IP
$msg.="$ref\n$timestamp\n$ip\n\n";                                        
//$msg.="$ref<br>$timestamp<br>$ip<br><br>";                              
 
//validate referring URL
//initialize switch     
$sw=0;                  
$ref_array = explode(",", $referrers);
foreach ($ref_array as $ref_ele){     
  if($ref_ele==$referrer)             
    $sw=1;                            
}                                     
if(!$sw)                              
  die("Error: Invalid referring domain");
 
 
//check reciepient is set
if($recipient=="")       
  die("Error: No recipient set");
 
//check recipient length
if(strlen($recipient)>200)
  die("Error: Recipient length too long");
 
//validate recipient
//get domain portion of recipient
$recip_email_arr=explode('@',$recipient);
$recip_dom=$recip_email_arr[1];          
 
//set from email
$from_email="webmaster@".$recip_dom;
 
//initialize switch
$sw=0;             
$rec_array = explode(",", $recipients);
foreach ($rec_array as $rec_ele){      
  if($rec_ele==$recip_dom)             
    $sw=1;                             
}                                      
if(!$sw)                               
  die("Error: Invalid recipient domain");
 
 
//The Guts
//required field error switch
$err_sw=0;                   
$err_msg="The following field(s) were left blank, please hit back and fill in:<br>";
 
foreach ($_POST as $field => $formvar){
  //switch to add to the message or not
  $sw=1;                               
 
  //Check if required field
  if($required!=""){       
    //build required field array
    $req_arr=explode(",",$required);
    foreach ($req_arr as $req_ele){ 
      if($req_ele==$field)          
        if($formvar==""){           
          $err_sw=1;                
          $err_msg.="* $field<br>"; 
        }                           
    }                               
  }                                 
 
 
  //Check for recipient
  if($field=="recipient")
    $sw=0;               
 
  //Check for subject
  if($field=="subject")
    $sw=0;             
 
  //Check for requied post var
  if($field=="required")      
    $sw=0;                    
 
 
  //Check for redirect URL
  if($field=="redirect")  
    $sw=0;                
 
  //for testing only
  #echo "$field: $formvar<br>";

  //Build the message
  if($sw)
    $msg.="$field: $formvar\n";
}
 
//display error message if required fields were left blank
if($err_sw)
  die($err_msg);
 
//Encrypt the message
if($secure){
 
  // Import the key into the keyring
  $result=shell_exec("/bin/echo $publickey | " . GPG . " --dearmor | " . GPG . " --import - 2>&1");
  // Find the key ID so that we can remove it later
  preg_match('/key ([A-Z0-9]+):/', $result, $matches);
  if (empty($matches[1])) {
   die('Problem importing key!');
  }
  $key_id=$matches[1];
 
  // Escape the key and message for added security
  $message=escapeshellarg(trim($msg));
 
  // Fire up GPG and encrypt the message
  $result=shell_exec("/bin/echo $message | " . GPG . " --batch --recipient '$key_id' --trust-model always --armor --encrypt 2>&1");
 
  $msg=$result;
 
  // Remove the key from the keyring
  $result=shell_exec(GPG . " --batch --yes --delete-key $key_id' 2>&1");
  if (!empty($result)) {
    die('Error: 29391');
  }
 
}
 
//Send the email
mail($recipient,$subject,$msg,"From: $from_email");
 
//Redirect the user if redirect set
if($redirect!="")
  header( "Location: $redirect" );
else
  header( "Location: http://$referrer" );
?>

The nice thing about this script is, its easy to use. Simply paste in your public key, and if you don’t have one, get one at freegpg.org, and then set the referrers URL, and if necessary change the path to gpg. This script has been tested and works well with the shared web hosting servers of Penguin Web Hosting

After the form is submitted, it sends you an email with the GPG encrypted message, and then you can decrypt it with your gpg compatible email client, or paste it in, along with your private key, at FreeGPG.org.

Secure FormMail can accept the 4 common hidden fields:

1
2
3
4
<input type=hidden name=recipient value="">
<input type=hidden name=required value="">
<input type=hidden name=redirect value="">
<input type=hidden name=subject value="">

Hope you find this useful!

TTYL,
Doug Walker

Comments are closed.