我在网站上遇到两个表单时遇到问题。由于网络钓鱼攻击导致我的主机多次删除托管表单的页面。
使用' PHPFormGenerator'构建的页面上的表单这是由托管公司(iPage)提供的软件。
我已经确定我使用了最新版本的PHPFormGenerator'推荐,但再次删除的页面。我安装了一个Captcha'在表格上,但页面已被删除。
我目前已从网页中删除了表单,并将其替换为电子邮件链接。
预订表单页面上的代码:
<div class="formRow">
<div class="formLeft">Name<span class="red">*</span></div>
<div class="formRight">
<input type=text name='Name' size=40>
</div>
</div>
<div class="formRow">
<div class="formLeft">Telephone<span class="red">*</span></div>
<div class="formRight">
<input type=text name='Telephone' size=40>
</div>
</div>
<div class="formRow">
<div class="formLeft">Email<span class="red">*</span></div>
<div class="formRight">
<input type=text name='Email' size=40>
</div>
</div>
<div class="formRow">
<div class="formLeft">Address1<span class="red">*</span></div>
<div class="formRight">
<input type=text name='Address1' size=40>
</div>
</div>
<div class="formRow">
<div class="formLeft">Address2<span class="red">*</span></div>
<div class="formRight">
<input type=text name='Address2' size=40>
</div>
</div>
<div class="formRow">
<div class="formLeft">Address3</div>
<div class="formRight">
<input type=text name='Address3' size=40>
</div>
</div>
<div class="formRow">
<div class="formLeft">Address4</div>
<div class="formRight">
<input type=text name='Address4' size=40>
</div>
</div>
<div class="formRow">
<div class="formLeft">Zip / Post code<span class="red">*</span></div>
<div class="formRight">
<input type=text name='PostCode' size=40>
</div>
</div>
<div class="formRow">
<div class="formLeft">Arrival<span class="red">*</span></div>
<div class="formRight">
<input type=text name='Arrival' size=15 id="datepicker">
</div>
</div>
<div class="formRow">
<div class="formLeft">Departure<span class="red">*</span></div>
<div class="formRight">
<input type=text name='Departure' size=15 id="datepicker2">
</div>
</div>
<div class="formRow">
<div class="formLeft">GroupNumber<span class="red">*</span></div>
<div class="formRight">
<select name='GroupNumber'>
<option value='01'>01</option>
<option value='02'>02</option>
<option value='03'>03</option>
<option value='04'>04</option>
<option value='05'>05</option>
<option value='06'>06</option>
</select>
</div>
</div>
<div class="formRow">
<div class="formLeft">Reason</div>
<div class="formRight">
<select name='Reason'>
<option value='Vacation'>Vacation</option>
<option value='Business'>Business</option>
<option value='Education'>Education</option>
<option value='Other'>Other</option>
</select>
</div>
</div>
<div class="formRow">
<div class="formLeft">Transfer</div>
<div class="formRight">
<input type=checkbox name='Transfer'>
</div>
</div>
<div class="formRow">
<div class="formLeft">CarRental</div>
<div class="formRight">
<input type=checkbox name='CarRental'>
</div>
</div>
<div class="formRow">
<div class="formLeft">Taxi</div>
<div class="formRight">
<input type=checkbox name='Taxi'>
</div>
</div>
<div class="formRow">
<div class="formLeft">Additional</div>
<div class="formRightBox">
<textarea name='Additional' rows=7 cols=31></textarea>
</div>
</div>
<div class="formRow">
<div class="formLeft"> </div>
<div class="formRightCaptcha">
<?php
require_once('recaptchalib.php');
$publickey = "6LfgGOASAAAAAOQ-oVZNlo8HmxR4GadyY4h5c0hY"; // you got this from the signup page
echo recaptcha_get_html($publickey);
?>
</div>
</div>
<div class="formRow">
<div class="formLeft"> </div>
<div class="formRight">
<input type=submit value='Submit Form'>
<input type=reset value='Reset Form'>
</div>
</div>
</div>
Verify.php
<?php
require_once('recaptchalib.php');
$privatekey = "***PRIVATEKEYREMOVED***";
$resp = recaptcha_check_answer ($privatekey,
$_SERVER["REMOTE_ADDR"],
$_POST["recaptcha_challenge_field"],
$_POST["recaptcha_response_field"]);
if (!$resp->is_valid) {
// What happens when the CAPTCHA was entered incorrectly
die ("The reCAPTCHA wasn't entered correctly. Go back and try it again." .
"(reCAPTCHA said: " . $resp->error . ")");
} else {
// Your code here to handle a successful verification
include("global.inc.php");
$errors=0;
$error="The following errors occured while processing your form input.<ul>";
pt_register('POST','Name');
pt_register('POST','Telephone');
pt_register('POST','Email');
pt_register('POST','Address1');
pt_register('POST','Address2');
pt_register('POST','Address3');
pt_register('POST','Address4');
pt_register('POST','PostCode');
pt_register('POST','Arrival');
pt_register('POST','Departure');
pt_register('POST','GroupNumber');
pt_register('POST','Reason');
pt_register('POST','Transfer');
pt_register('POST','CarRental');
pt_register('POST','Taxi');
pt_register('POST','Additional');
$Additional=preg_replace("/(\015\012)|(\015)|(\012)/"," <br />", $Additional);if($Name=="" || $Telephone=="" || $Email=="" || $Address1=="" || $Address2=="" || $PostCode=="" || $Arrival=="" || $Departure=="" || $GroupNumber=="" ){
$errors=1;
$error.="<li>You did not enter one or more of the required fields. Please go back and try again.";
}
if(!eregi("^[a-z0-9]+([_\\.-][a-z0-9]+)*" ."@"."([a-z0-9]+([\.-][a-z0-9]+)*)+"."\\.[a-z]{2,}"."$",$Email)){
$error.="<li>Invalid email address entered";
$errors=1;
}
if($errors==1) echo $error;
else{
$where_form_is="http".($HTTP_SERVER_VARS["HTTPS"]=="on"?"s":"")."://".$SERVER_NAME.strrev(strstr(strrev($PHP_SELF),"/"));
$message="A booking enquiry has been made by ".$Name."
Telephone: ".$Telephone."
Email: ".$Email."
Address1: ".$Address1."
Address2: ".$Address2."
Address3: ".$Address3."
Address4: ".$Address4."
PostCode: ".$PostCode."
Arrival: ".$Arrival."
Departure: ".$Departure."
GroupNumber: ".$GroupNumber."
Reason: ".$Reason."
Transfer: ".$Transfer."
CarRental: ".$CarRental."
Taxi: ".$Taxi."
Additional: ".$Additional."
";
$message = stripslashes($message);
$subject = 'Louis Villa booking enquiry';
$headers = 'From:' .$Name. ' made a booking enquiry' . "\r\n" . // <- change your email here
'Reply-To:' . $Email . "\r\n";
mail("info@louisvilla.com",$subject,$message,$headers);
header("Location:http://louisvilla.com/thankyou.html");
exit();
}
}
?>
Global.inc.php
<?php
function pt_register()
{
$num_args = func_num_args();
$vars = array();
if ($num_args >= 2) {
$method = strtoupper(func_get_arg(0));
if (($method != 'SESSION') && ($method != 'GET') && ($method != 'POST') && ($method != 'SERVER') && ($method != 'COOKIE') && ($method != 'ENV')) {
die('The first argument of pt_register must be one of the following: GET, POST, SESSION, SERVER, COOKIE, or ENV');
}
$varname = "HTTP_{$method}_VARS";
global ${$varname};
for ($i = 1; $i < $num_args; $i++) {
$parameter = func_get_arg($i);
if (isset(${$varname}[$parameter])) {
global $$parameter;
$$parameter = ${$varname}[$parameter];
}
}
} else {
die('You must specify at least two arguments');
}
}
?>
recaptchalib.php
<?php
define("RECAPTCHA_API_SERVER", "http://www.google.com/recaptcha/api");
define("RECAPTCHA_API_SECURE_SERVER", "https://www.google.com/recaptcha/api");
define("RECAPTCHA_VERIFY_SERVER", "www.google.com");
/**
* Encodes the given data into a query string format
* @param $data - array of string elements to be encoded
* @return string - encoded request
*/
function _recaptcha_qsencode ($data) {
$req = "";
foreach ( $data as $key => $value )
$req .= $key . '=' . urlencode( stripslashes($value) ) . '&';
// Cut the last '&'
$req=substr($req,0,strlen($req)-1);
return $req;
}
/**
* Submits an HTTP POST to a reCAPTCHA server
* @param string $host
* @param string $path
* @param array $data
* @param int port
* @return array response
*/
function _recaptcha_http_post($host, $path, $data, $port = 80) {
$req = _recaptcha_qsencode ($data);
$http_request = "POST $path HTTP/1.0\r\n";
$http_request .= "Host: $host\r\n";
$http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
$http_request .= "Content-Length: " . strlen($req) . "\r\n";
$http_request .= "User-Agent: reCAPTCHA/PHP\r\n";
$http_request .= "\r\n";
$http_request .= $req;
$response = '';
if( false == ( $fs = @fsockopen($host, $port, $errno, $errstr, 10) ) ) {
die ('Could not open socket');
}
fwrite($fs, $http_request);
while ( !feof($fs) )
$response .= fgets($fs, 1160); // One TCP-IP packet
fclose($fs);
$response = explode("\r\n\r\n", $response, 2);
return $response;
}
/**
* Gets the challenge HTML (javascript and non-javascript version).
* This is called from the browser, and the resulting reCAPTCHA HTML widget
* is embedded within the HTML form it was called from.
* @param string $pubkey A public key for reCAPTCHA
* @param string $error The error given by reCAPTCHA (optional, default is null)
* @param boolean $use_ssl Should the request be made over ssl? (optional, default is false)
* @return string - The HTML to be embedded in the user's form.
*/
function recaptcha_get_html ($pubkey, $error = null, $use_ssl = false)
{
if ($pubkey == null || $pubkey == '') {
die ("To use reCAPTCHA you must get an API key from <a href='https://www.google.com/recaptcha/admin/create'>https://www.google.com/recaptcha/admin/create</a>");
}
if ($use_ssl) {
$server = RECAPTCHA_API_SECURE_SERVER;
} else {
$server = RECAPTCHA_API_SERVER;
}
$errorpart = "";
if ($error) {
$errorpart = "&error=" . $error;
}
return '<script type="text/javascript" src="'. $server . '/challenge?k=' . $pubkey . $errorpart . '"></script>
<noscript>
<iframe src="'. $server . '/noscript?k=' . $pubkey . $errorpart . '" height="300" width="500" frameborder="0"></iframe><br/>
<textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
<input type="hidden" name="recaptcha_response_field" value="manual_challenge"/>
</noscript>';
}
/**
* A ReCaptchaResponse is returned from recaptcha_check_answer()
*/
class ReCaptchaResponse {
var $is_valid;
var $error;
}
/**
* Calls an HTTP POST function to verify if the user's guess was correct
* @param string $privkey
* @param string $remoteip
* @param string $challenge
* @param string $response
* @param array $extra_params an array of extra variables to post to the server
* @return ReCaptchaResponse
*/
function recaptcha_check_answer ($privkey, $remoteip, $challenge, $response, $extra_params = array())
{
if ($privkey == null || $privkey == '') {
die ("To use reCAPTCHA you must get an API key from <a href='https://www.google.com/recaptcha/admin/create'>https://www.google.com/recaptcha/admin/create</a>");
}
if ($remoteip == null || $remoteip == '') {
die ("For security reasons, you must pass the remote ip to reCAPTCHA");
}
//discard spam submissions
if ($challenge == null || strlen($challenge) == 0 || $response == null || strlen($response) == 0) {
$recaptcha_response = new ReCaptchaResponse();
$recaptcha_response->is_valid = false;
$recaptcha_response->error = 'incorrect-captcha-sol';
return $recaptcha_response;
}
$response = _recaptcha_http_post (RECAPTCHA_VERIFY_SERVER, "/recaptcha/api/verify",
array (
'privatekey' => $privkey,
'remoteip' => $remoteip,
'challenge' => $challenge,
'response' => $response
) + $extra_params
);
$answers = explode ("\n", $response [1]);
$recaptcha_response = new ReCaptchaResponse();
if (trim ($answers [0]) == 'true') {
$recaptcha_response->is_valid = true;
}
else {
$recaptcha_response->is_valid = false;
$recaptcha_response->error = $answers [1];
}
return $recaptcha_response;
}
/**
* gets a URL where the user can sign up for reCAPTCHA. If your application
* has a configuration page where you enter a key, you should provide a link
* using this function.
* @param string $domain The domain where the page is hosted
* @param string $appname The name of your application
*/
function recaptcha_get_signup_url ($domain = null, $appname = null) {
return "https://www.google.com/recaptcha/admin/create?" . _recaptcha_qsencode (array ('domains' => $domain, 'app' => $appname));
}
function _recaptcha_aes_pad($val) {
$block_size = 16;
$numpad = $block_size - (strlen ($val) % $block_size);
return str_pad($val, strlen ($val) + $numpad, chr($numpad));
}
/* Mailhide related code */
function _recaptcha_aes_encrypt($val,$ky) {
if (! function_exists ("mcrypt_encrypt")) {
die ("To use reCAPTCHA Mailhide, you need to have the mcrypt php module installed.");
}
$mode=MCRYPT_MODE_CBC;
$enc=MCRYPT_RIJNDAEL_128;
$val=_recaptcha_aes_pad($val);
return mcrypt_encrypt($enc, $ky, $val, $mode, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
}
function _recaptcha_mailhide_urlbase64 ($x) {
return strtr(base64_encode ($x), '+/', '-_');
}
/* gets the reCAPTCHA Mailhide url for a given email, public key and private key */
function recaptcha_mailhide_url($pubkey, $privkey, $email) {
if ($pubkey == '' || $pubkey == null || $privkey == "" || $privkey == null) {
die ("To use reCAPTCHA Mailhide, you have to sign up for a public and private key, " .
"you can do so at <a href='http://www.google.com/recaptcha/mailhide/apikey'>http://www.google.com/recaptcha/mailhide/apikey</a>");
}
$ky = pack('H*', $privkey);
$cryptmail = _recaptcha_aes_encrypt ($email, $ky);
return "http://www.google.com/recaptcha/mailhide/d?k=" . $pubkey . "&c=" . _recaptcha_mailhide_urlbase64 ($cryptmail);
}
/**
* gets the parts of the email to expose to the user.
* eg, given johndoe@example,com return ["john", "example.com"].
* the email is then displayed as john...@example.com
*/
function _recaptcha_mailhide_email_parts ($email) {
$arr = preg_split("/@/", $email );
if (strlen ($arr[0]) <= 4) {
$arr[0] = substr ($arr[0], 0, 1);
} else if (strlen ($arr[0]) <= 6) {
$arr[0] = substr ($arr[0], 0, 3);
} else {
$arr[0] = substr ($arr[0], 0, 4);
}
return $arr;
}
/**
* Gets html to display an email address given a public an private key.
* to get a key, go to:
*
* http://www.google.com/recaptcha/mailhide/apikey
*/
function recaptcha_mailhide_html($pubkey, $privkey, $email) {
$emailparts = _recaptcha_mailhide_email_parts ($email);
$url = recaptcha_mailhide_url ($pubkey, $privkey, $email);
return htmlentities($emailparts[0]) . "<a href='" . htmlentities ($url) .
"' onclick=\"window.open('" . htmlentities ($url) . "', '', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=300'); return false;\" title=\"Reveal this e-mail address\">...</a>@" . htmlentities ($emailparts [1]);
}
?>
任何帮助将不胜感激。我一直与我的托管公司保持联系,寻求支持,因为表格是用他们推荐的软件构建的,他们提供的唯一帮助就是去网上论坛寻求帮助。
我创建了许多联系表单&#39;以前从来没有遇到过这个问题。
提前感谢您的帮助。
答案 0 :(得分:2)
问题在于您发布的代码很容易被邮件标头攻击。
此代码的目的是始终向您发送电子邮件,并且仅向您发送电子邮件,但您的电子邮件标题可能会受到操纵,以致电子邮件会被非预期的内容重写并发送给任意收件人。
换句话说,对于知道如何攻击它的人来说,你有一个开放的电子邮件系统,可以完全匿名地向任何人发送任何内容。
问题的核心在于:
$headers = 'From:' .$Name. ' made a booking enquiry' . "\r\n" .
'Reply-To:' . $Email . "\r\n";
$Name
和$Email
都可以通过注入其他\r\n
序列和其他标头来攻击系统。
您需要清理这些字段以及您可能用来阻止此类攻击的任何其他标头。
这种事情暴露了PHP内置mail()
函数的弱点。使用此功能编写易受攻击的邮件程序非常容易。
我的建议是使用更好的邮件程序类,例如phpMailer而不是PHP的内置mail()
函数。
phpMailer为您清理输入并使攻击者难以破解您的系统做了所有艰苦的工作。是的,您可以修改您的代码来自己处理所有这些,但这是很多工作,您永远不会完全确定您已经涵盖了所有内容。所以使用像phpMailer这样的类,因为他们已经为你完成了所有工作。
基本上,一旦你安装了phpMailer,你就会替换这段代码:
$subject = 'Louis Villa booking enquiry';
$headers = 'From:' .$Name. ' made a booking enquiry' . "\r\n" .
'Reply-To:' . $Email . "\r\n";
mail("info@louisvilla.com",$subject,$message,$headers);
......用这个:
require 'class.phpmailer.php';
$mail = new PHPMailer;
$mail->From = $Email;
$mail->FromName = $Name;
$mail->AddAddress('info@louisvilla.com');
$mail->Subject = $subject;
$mail->Body = $message;
if(!$mail->Send()) {
echo 'Message could not be sent.';
echo 'Mailer Error: ' . $mail->ErrorInfo;
exit;
}
更整洁的代码,更安全。全面胜利。
希望有所帮助。
答案 1 :(得分:1)
如果托管公司因“网络钓鱼攻击”(声称您容易受到攻击)而删除内容,您可以放弃或起诉他们是不负责任的主机。网络钓鱼实际上是任何网站都容易受到攻击的东西;它是对人类的攻击,而不是对网站的攻击。</ p>
与social engineering类似,您可以做的唯一事情就是教育用户。 (注意:您也可以使用带有正确DKIM / SPF记录的签名电子邮件,Gmail也不会轻易将您标记为垃圾邮件,但这是您可以访问的限制)
此外(虽然这部分理想情况下应该进行代码审查)
$_SERVER
(这是正确的)和$HTTP_SERVER_VARS
(已deprecated for many years并在错误日志中抛出E_DEPRECATED
。HTTP_*_VARS
进行了全局调整;这不是必需的,因为$_POST/GET/SESSION/...
都是超级全球。我能想到的唯一一件事就是让你的主机合法地删除内容,如果他们认为你是一个网络钓鱼,但是考虑到他们在此之后在论坛上寻求帮助的回应,我会说他们只是非常不专业。
编辑:在我看到自己看不到@Spudley看到的内容之后,似乎有人一直在使用您的脚本向人们发送网络钓鱼攻击。您的托管公司知道您的脚本正在发送它们,但只是删除它们并且没有告诉您它正在被利用(并且可能没有假设诚信)