2013-05-13 56 views
1

我在網站上遇到兩種表單有問題。由於「釣魚攻擊」,託管表單的頁面已被我的主機多次拆除。通過PHP形式的釣魚攻擊

使用託管公司(iPage)提供的軟件「PHPFormGenerator」構建的頁面上的表單。

我已經確定我正在推薦最新版本的'PHPFormGenerator'作爲推薦的,但是再次提到了取下來的頁面。我在表單上安裝了一個「驗證碼」,但頁面已被刪除。

我目前已經從頁面中刪除了表單,並用電子郵件鏈接替換了它們。

代碼訂艙單頁:

<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'> 
     &nbsp; 
     <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)/","&nbsp;<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("[email protected]",$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 = "&amp;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 [email protected],com return ["john", "example.com"]. 
* the email is then displayed as [email protected] 
*/ 
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]); 

} 


?> 

任何幫助,將不勝感激。我一直與我的託管公司聯繫,尋求支持,因爲表單是用他們推薦的軟件構建的,他們提供的唯一幫助是去網上論壇並尋求幫助。

我已經創建了許多'聯繫表'等等,從未有過這個問題。

在此先感謝您的幫助。

+1

網絡釣魚攻擊是用類似於你的表單/鏈接對人類進行的攻擊,與代碼無關(當然,你可以阻止它,但這會涉及HTTPS和一些大的警告,以檢查瀏覽器欄的人誰不明白)。你的託管公司是完全愚蠢的(現在如果它是CSRF/XSS,那將是你的問題)。 – Amelia 2013-05-13 11:49:44

+1

另外,使用'$ _SERVER','$ _POST'等。'HTTP _ * _ VARS'在幾年前就被棄用了。 – Amelia 2013-05-13 11:54:37

回答

1

如果託管公司因「釣魚攻擊」(聲稱你很容易受到攻擊)而刪除內容,則可以將其丟棄或因不負責任的主機而起訴他們。網絡釣魚是任何網站都容易受到攻擊的東西;這是對人類的攻擊,而不是一個網站。

social engineering類似,幾乎你唯一能做的就是教育用戶。 (注意:您也可以使用帶有適當DKIM/SPF記錄的簽名電子郵件,並且Gmail也不會輕易將您標記爲垃圾郵件,但這是您可以進行的限制)

此外(儘管此部分應在代碼審查最好)

  • 你混合$_SERVER(這是正確的),並$HTTP_SERVER_VARS(這一直deprecated for many years,並在錯誤日誌中拋出E_DEPRECATED)。
  • 您似乎已整合了HTTP_*_VARS;這是不需要的,因爲$_POST/GET/SESSION/...都是超全球。
  • 您的電子郵件正式的表達無效; regex can't validate email(電子郵件語法不規則,因此正則表達式不會100%的時間工作)。
  • 您無法防範CSRF。關於它,請參見Jeff's blog post。,

我能想到的唯一的事情會導致你的主機合法地取下來的內容是,如果他們認爲你是一個釣魚網站但是由於其對後這一發現在一個論壇上的幫助的反應,我說他們只是非常不專業。

編輯:因爲我沒有看到@Spudley看到的內容,所以似乎人們已經在使用您的腳本向人們發送網絡釣魚攻擊。您的託管公司知道您的腳本正在發送它們,但只是將其刪除,並沒有告訴您它正在被利用(並且可能沒有假設誠信)

+0

嗨Hiroto,感謝您的回覆。我非常沮喪的託管公司,但我沒有選擇他們。我的客戶已經在使用他們,我會建議改變。 但是,如果他們不想承擔費用,那麼您對代碼的推薦更改是否有助於解決問題? – 2013-05-13 12:25:17

+1

想到我很快會補充一點,爲了驗證電子郵件,您所能做的就是檢查通過的地址是否至少是**電子郵件地址**。爲此,給'filter_var($ email,FILTER_VALIDATE_EMAIL)'一試。 – Jimbo 2013-05-13 12:29:35

+0

@JuniorChubb請參閱Spudley針對漏洞修復的回答,但這兩個答案結合在一起會提供更好,更安全的代碼(特別是CSRF +正則表達式註釋)。 – Amelia 2013-05-13 12:31:17

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("[email protected]",$subject,$message,$headers); 

...這一點:

require 'class.phpmailer.php'; 
$mail = new PHPMailer; 
$mail->From = $Email; 
$mail->FromName = $Name; 
$mail->AddAddress('[email protected]'); 
$mail->Subject = $subject; 
$mail->Body = $message; 
if(!$mail->Send()) { 
    echo 'Message could not be sent.'; 
    echo 'Mailer Error: ' . $mail->ErrorInfo; 
    exit; 
} 

整潔的代碼,安全性更高。全面勝利。

希望有所幫助。

+0

我完全錯過了這個,哇。 Brb在頭上撞擊自己。 – Amelia 2013-05-13 12:29:14

+0

感謝Spudley和Lol Hiroto。 在考慮託管變更之前,我會先給出這個。 – 2013-05-20 20:00:19