#1
  1. A Change of Season
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Mar 2004
    Location
    Next Door
    Posts
    2,670
    Rep Power
    171

    Securing a folder that updates the database


    Hello forum;

    I need to confirm I am doing the right thing here.

    I have a folder called "ipn". The folder is only used when Pay pal calls it (That's just poor English). In other words, its not allowed to access any of the pages in this directly from the address bar (ie. www.domain.com/ipn/update_customer.php is not allowed).

    Files in this folder update the database based on the $_GET values received from Pay pal:

    For example:

    PHP Code:
    //Check and validating the $_GET values....
    //.....
    //If all good, then:
    $qupdate="UPDATE customers_credits SET status = 'active', history = '".$history."' WHERE id = '".$clean_data_get['id']."'"
    And this is what I send to Pay pal:

    Code:
    <input type="hidden" name="notify_url" value="http://www.domain.com/ipn/voucher_ipn_res.php?id=<?php echo $_GET['id'];?>"  />
    Here is my solution (which seems to be working just fine):

    I create a .htaccess file in that folder with this content:

    Code:
      Order Deny,Allow
      Deny from All
      Allow from paypal.com
    I appreciate if you point the security holes in that.

    Thanks
    Last edited by zxcvbnm; January 5th, 2012 at 05:43 PM.
  2. #2
  3. Transforming Moderator
    Devshed Supreme Being (6500+ posts)

    Join Date
    Mar 2007
    Location
    Washington, USA
    Posts
    14,110
    Rep Power
    9398
    That's about it, really. But are there multiple files in that folder? The IPN script itself should be safe by virtue of how it works: it verifies the request against PayPal's servers and doesn't continue if it gets a bad response.

    Otherwise I could be pedantic about the Order directive, but I don't feel like it. (It's fine.)
  4. #3
  5. A Change of Season
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Mar 2004
    Location
    Next Door
    Posts
    2,670
    Rep Power
    171
    Originally Posted by requinix
    That's about it, really. But are there multiple files in that folder? The IPN script itself should be safe by virtue of how it works: it verifies the request against PayPal's servers and doesn't continue if it gets a bad response.
    Otherwise I could be pedantic about the Order directive, but I don't feel like it. (It's fine.)
    Thanks yes there is only this file in the folder.
  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    May 2011
    Location
    United Kingdom
    Posts
    42
    Rep Power
    5
    It would be possible to perform an attack at the DNS level to modify your hosts resolution of paypal.com to that of the attacker.
  8. #5
  9. Mad Scientist
    Devshed Expert (3500 - 3999 posts)

    Join Date
    Oct 2007
    Location
    North Yorkshire, UK
    Posts
    3,661
    Rep Power
    4123
    I've you've coded up your ipn script properly then the world and his wife you view it and you'd still be safe.

    Did you start your ipn script by copying the php sample code from paypal?
    I said I didn't like ORM!!! <?php $this->model->update($this->request->resources[0])->set($this->request->getData())->getData('count'); ?>

    PDO vs mysql_* functions: Find a Migration Guide Here

    [ Xeneco - T'interweb Development ] - [ Are you a Help Vampire? ] - [ Read The manual! ] - [ W3 methods - GET, POST, etc ] - [ Web Design Hell ]
  10. #6
  11. A Change of Season
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Mar 2004
    Location
    Next Door
    Posts
    2,670
    Rep Power
    171
    Originally Posted by Northie
    I've you've coded up your ipn script properly then the world and his wife you view it and you'd still be safe.
    Hey this is strange English, pretty sure you have a good point but I don't understand.

    Originally Posted by Northie
    Did you start your ipn script by copying the php sample code from paypal?
    The ipn/update_customer.php script is just a simple database update script like this:
    PHP Code:
    $sql "SELECT id FROM orders WHERE id=:id AND status=:status";
    $args = array('id'=>$_GET['id'], 'status'=>'pending' );

    //Chris probably won't like this but:
    $number_of_rows DB::Load()->Execute($sql,$args)->returnNumAffectedRows();


    if(
    $number_of_rows==1)
     {
         
    //$sql = "UPDATE...";
           
    $args =...;
           
    $execute...
     }
    else
     {
        
    //invalid 
      

  12. #7
  13. Mad Scientist
    Devshed Expert (3500 - 3999 posts)

    Join Date
    Oct 2007
    Location
    North Yorkshire, UK
    Posts
    3,661
    Rep Power
    4123
    Originally Posted by zxcvbnm
    Hey this is strange English, pretty sure you have a good point but I don't understand.
    sorry, that should have been

    Originally Posted by Northie
    If you've coded up your ipn script properly then the world and his wife could view it and you'd still be safe.
    Originally Posted by zxcvbnm
    The ipn/update_customer.php script is just a simple database update script like this: ...
    There's your problem, you're doing no validation checks with paypal. The code you've written should live deep inside an "if" statement.... read on for more, and some sample code

    In an ipn call, paypal calls a script on your server. You are supposed to send these post values back to paypal in server-generated post request and read the response from it. Paypal's response to this post tells you if the transaction is legitimate, or not. Paypal knows if they, themselves, made the request to your ipn script and responds accordingly when asked to do so.

    paypal sample code php code here:

    https://cms.paypal.com/cms_content/U...IPN_PHP_41.txt

    As for protecting your folder so that just paypal can access it - try this: The paypal sandbox will allow me to test any IPN script i know about, the request will come from a paypal.com domain
    Last edited by Northie; January 6th, 2012 at 02:36 AM.
    I said I didn't like ORM!!! <?php $this->model->update($this->request->resources[0])->set($this->request->getData())->getData('count'); ?>

    PDO vs mysql_* functions: Find a Migration Guide Here

    [ Xeneco - T'interweb Development ] - [ Are you a Help Vampire? ] - [ Read The manual! ] - [ W3 methods - GET, POST, etc ] - [ Web Design Hell ]
  14. #8
  15. No Profile Picture
    Contributing Badly User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2007
    Posts
    143
    Rep Power
    10
    I am sure there is a system check that is available to you, as a part of your integrity checks.

    Not 100% sure but i would think paypal has a call you can make to find out which system made the call to your server, live or sandbox.

    as pointed out you can make a call to any ipn script with the sandbox, so there must be a system type call you can make.
    If i went into too much detail or assumed this was what you meant, well thats just how i thought you wanted it
  16. #9
  17. A Change of Season
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Mar 2004
    Location
    Next Door
    Posts
    2,670
    Rep Power
    171
    Originally Posted by Northie
    There's your problem, you're doing no validation checks with paypal. The code you've written should live deep inside an "if" statement.... read on for more, and some sample code

    In an ipn call, paypal calls a script on your server. You are supposed to send these post values back to paypal in server-generated post request and read the response from it. Paypal's response to this post tells you if the transaction is legitimate, or not. Paypal knows if they, themselves, made the request to your ipn script and responds accordingly when asked to do so.

    paypal sample code php code here:

    https://cms.paypal.com/cms_content/U...IPN_PHP_41.txt

    As for protecting your folder so that just paypal can access it - try this: The paypal sandbox will allow me to test any IPN script i know about, the request will come from a paypal.com domain
    Hello;

    I am a bit closer to your solution. I used the following code and the Sandbox says IPN successfully sent but I get the Invalid email. In other words in the ipn.php the check with Paypal is NOT verified. Please see below:

    PHP Code:
    <?php  
        
    // read the post from PayPal system and add 'cmd'  
        
    $req 'cmd=_notify-validate';  
        foreach (
    $_POST as $key => $value)
            {  
                
    $value urlencode(stripslashes($value));  
                
    $req .= "&$key=$value";  
            }  
        
    // post back to PayPal system to validate  
        
    $header "POST /cgi-bin/webscr HTTP/1.0\r\n";  
        
    $header .= "Content-Type: application/x-www-form-urlencoded\r\n";  
        
    $header .= "Content-Length: ".strlen($req)."\r\n\r\n";  
        
    $fp fsockopen ('ssl://www.paypal.com'443$errno$errstr30);  
        if (!
    $fp)
            {  
                
    // HTTP ERROR  
            
    }
        else
            {  
                
    fputs ($fp$header.$req);  
                while(!
    feof($fp))
                    {  
                        
    $res fgets ($fp1024);  
                        if (
    strcmp ($res"VERIFIED") == 0)
                            {  
                                
    // PAYMENT VALIDATED & VERIFIED!
                                
    $email $_POST['payer_email'];
                                
    mail($email$subject$message$headers);
                                
    // PAYMENT VALIDATED & VERIFIED!
                            
    }  
                        elseif(
    strcmp ($res"INVALID") == 0)
                                {  
                                    
    $email $_POST['payer_email'];
                                    foreach(
    $_POST as $var)
                                        {
                                            
    $message .= "\r\n".$var;
                                        }
                                    
    mail($email'Invalid'$message$headers);
                                }  
                    }  
                
    fclose ($fp);  
            }  
    ?>
    And I keep getting an email with the title Invalid with the follwoing content:

    Code:
    1
    instant
    16:27:50 Jan 18, 2012 PST
    Completed
    confirmed
    verified
    John
    Smith
    pmdg3@yahoo.com
    TESTBUYERID01
    John Smith
    United States
    US
    95131
    CA
    San Jose
    123, any street
    seller@paypalsandbox.com
    seller@paypalsandbox.com
    TESTSELLERID1
    US
    something
    AK-1234
    1
    3.04
    2.02
    USD
    0.44
    12.34
    9.34
    web_accept
    50119027
    2.1
    xyz123
    windows-1252
    Ay6yLHy3emJ0Ljt4I6eJB1vMeiv7AN8R9NE95JCSLrf.qgUlNmZn9Hu8
    So basically this part of the code does not meet the criteria:

    if (strcmp ($res, "VERIFIED") == 0)

    What do you think is wrong?

    Merci
  18. #10
  19. Mad Scientist
    Devshed Expert (3500 - 3999 posts)

    Join Date
    Oct 2007
    Location
    North Yorkshire, UK
    Posts
    3,661
    Rep Power
    4123
    Paypal is always a pain.

    When testing your ipn script from paypals developer/sandbox then the domain to which you open a socket to needs to be the sandbox domain/url not the normal one!
    I said I didn't like ORM!!! <?php $this->model->update($this->request->resources[0])->set($this->request->getData())->getData('count'); ?>

    PDO vs mysql_* functions: Find a Migration Guide Here

    [ Xeneco - T'interweb Development ] - [ Are you a Help Vampire? ] - [ Read The manual! ] - [ W3 methods - GET, POST, etc ] - [ Web Design Hell ]
  20. #11
  21. A Change of Season
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Mar 2004
    Location
    Next Door
    Posts
    2,670
    Rep Power
    171
    In case anyone runs into this thread, note that Paypal has a new php listener. So do not use the code above, instead use the new version:
    PHP Code:
    // STEP 1: Read POST data
     
    // reading posted data from directly from $_POST causes serialization 
    // issues with array data in POST
    // reading raw POST data from input stream instead. 
    $raw_post_data file_get_contents('php://input');
    $raw_post_array explode('&'$raw_post_data);
    $myPost = array();
    foreach (
    $raw_post_array as $keyval) {
      
    $keyval explode ('='$keyval);
      if (
    count($keyval) == 2)
         
    $myPost[$keyval[0]] = urldecode($keyval[1]);
    }
    // read the post from PayPal system and add 'cmd'
    $req 'cmd=_notify-validate';
    if(
    function_exists('get_magic_quotes_gpc')) {
       
    $get_magic_quotes_exists true;

    foreach (
    $myPost as $key => $value) {        
       if(
    $get_magic_quotes_exists == true && get_magic_quotes_gpc() == 1) { 
            
    $value urlencode(stripslashes($value)); 
       } else {
            
    $value urlencode($value);
       }
       
    $req .= "&$key=$value";
    }
     
     
    // STEP 2: Post IPN data back to paypal to validate
     
    $ch curl_init('https://www.paypal.com/cgi-bin/webscr');
    curl_setopt($chCURLOPT_HTTP_VERSIONCURL_HTTP_VERSION_1_1);
    curl_setopt($chCURLOPT_POST1);
    curl_setopt($chCURLOPT_RETURNTRANSFER,1);
    curl_setopt($chCURLOPT_POSTFIELDS$req);
    curl_setopt($chCURLOPT_SSL_VERIFYPEER1);
    curl_setopt($chCURLOPT_SSL_VERIFYHOST2);
    curl_setopt($chCURLOPT_FORBID_REUSE1);
    curl_setopt($chCURLOPT_HTTPHEADER, array('Connection: Close'));
     
    // In wamp like environments that do not come bundled with root authority certificates,
    // please download 'cacert.pem' from "http://curl.haxx.se/docs/caextract.html" and set the directory path 
    // of the certificate as shown below.
    // curl_setopt($ch, CURLOPT_CAINFO, dirname(__FILE__) . '/cacert.pem');
    if( !($res curl_exec($ch)) ) {
        
    // error_log("Got " . curl_error($ch) . " when processing IPN data");
        
    curl_close($ch);
        exit;
    }
    curl_close($ch);
     
     
    // STEP 3: Inspect IPN validation result and act accordingly
     
    if (strcmp ($res"VERIFIED") == 0) { 
        
    // check whether the payment_status is Completed
        // check that txn_id has not been previously processed
        // check that receiver_email is your Primary PayPal email
        // check that payment_amount/payment_currency are correct
        // process payment
     
        // assign posted variables to local variables
        
    $item_name $_POST['item_name'];
        
    $item_number $_POST['item_number'];
        
    $payment_status $_POST['payment_status'];
        
    $payment_amount $_POST['mc_gross'];
        
    $payment_currency $_POST['mc_currency'];
        
    $txn_id $_POST['txn_id'];
        
    $receiver_email $_POST['receiver_email'];
        
    $payer_email $_POST['payer_email'];
    } else if (
    strcmp ($res"INVALID") == 0) {
        
    // log for manual investigation


IMN logo majestic logo threadwatch logo seochat tools logo