dongqiaogouk86049
2016-02-14 11:11
浏览 124
已采纳

使用cURL检索网站HTML页面,其中包含当前会话和安全页面上的cookie数据

Question fully revised on: Feb. 19th

The thing i want (in short):

I would like to get an HTML page using cURL that is secured with a user login(at time of cURL request the user is logged in with rights to the page).

More detailed:

The situation is that the user is on a webpage like index.php?w=2344&y=lalala&x=something which is secured(by security script class.Firewizz.Security.php). On that page there is a "print as pdf" button. This sends the user to the page getPDF.php this page sees where the request is coming from and gets that page using cURL and that output will be send to the browser as PDF print.

But for now i set the page variable static in the getPDF.php page so it does not check the referrer and i am 100% sure the page it try's to get is correct.

Also the output is just echoed as is and is not yet converted to PDF just so that won't interfere with the problem.

Expected output is now the same as it would be if the user goes to the page. except this is not the case, the user gets nothing.

What do we know? We know that the $_SESSION data is NOT being send to the cURL, i know this for a fact because i echoed the $_SESSION data on the output file which says they are empty.

After a lot of trying we still have no solution what so ever, still no '$_SESSION' data.

I do not want to compromise security script in any way, so the solution "remove ini_set('session.use_only_cookies', 1); is NOT what i am looking for."

On request(for the ones that are dedicated to help) i can send full script files but i will post relevant snippets below.

class.Firewizz.Security.php

<?php

/*
 * Firewizz UserLogin
 */

namespace Firewizz;



class Security
{

     // Start the session, with Cookie data
    public function Start_Secure_Session()
    {
        // Forces sessions to only use cookies.
        ini_set('session.use_only_cookies', 1);

        // Gets current cookies params
        $cookieParams = session_get_cookie_params();

        // Set Cookie Params
        session_set_cookie_params($cookieParams["lifetime"], $cookieParams["path"], $cookieParams["domain"], $this->isHTTPS, $this->deny_java_session_id);
        // Sets the session name
        session_name($this->session_name);

        // Start the php session
        session_start();

        // If new session or expired, generate new id
        if (!isset($_SESSION['new_session']))
        {
            $_SESSION['new_session'] = "true";

            // regenerate the session, delete the old one.
            session_regenerate_id(true);
        }
    }

    // Check of user is logged in to current session, return true or false;
    public function LOGGED_IN()
    {
        return $this->_login_check();
    }

    public function LOGOUT()
    {
    // Unset all session values
        $_SESSION = array();

        // get session parameters
        $params = session_get_cookie_params();

        // Delete the actual cookie.
        setcookie(session_name(), '', time() - 42000, $params["path"], $params["domain"], $params["secure"], $params["httponly"]);
        // Destroy session
        session_destroy();
        if (!headers_sent())
        {
            header("Location: " . $this->login_string, true);
        }
        else
        {
            echo '<script>window.location="/"</script>';
        }
    }

    // Must pass variables or send to login page!
    public function BORDER_PATROL($user_has_to_be_logged_in, $page_loaded_from_index)
    {
        $pass_border_partrol = true;

        if (!$this->LOGGED_IN() && $user_has_to_be_logged_in)
        {
            $pass_border_partrol = false;
        }
        if (filter_input(INPUT_SERVER, "PHP_SELF") != "/index.php" && $page_loaded_from_index)
        {
            $pass_border_partrol = false;
        }

        // Kick to login on fail
        if (!$pass_border_partrol)
        {
            $this->LOGOUT();
            exit();
        }

    }

    // Catch login, returns fail string or false if no errors
    public function CATCH_LOGIN()
    {
        if (filter_input(INPUT_POST, "id") == "login" && filter_input(INPUT_POST, "Verzenden") == "Verzenden")
        {
            // Variables from form.
            $email = filter_input(INPUT_POST, "email");
            $sha512Pass = filter_input(INPUT_POST, "p");

            // Database variables
            $db_accounts = mysqli_connect($this->mySQL_accounts_host, $this->mySQL_accounts_username, $this->mySQL_accounts_password, $this->mySQL_accounts_database);

            // Prepage sql
            if ($stmt = $db_accounts->prepare("SELECT account_id, verified, blocked ,login_email, login_password, login_salt, user_voornaam, user_tussenvoegsel, user_achternaam FROM accounts WHERE login_email = ? LIMIT 1"))
            {
                $stmt->bind_param('s', $email); // Bind "$email" to parameter.
                $stmt->execute(); // Execute the prepared query.
                $stmt->store_result();

                $stmt->bind_result($user_id, $verified, $blocked, $email, $db_password, $salt, $voornaam, $tussenvoegsel, $achternaam); // get variables from result.

                $stmt->fetch();
                $password = hash('sha512', $sha512Pass . $salt); // hash the password with the unique salt.
                $tussen = ' ';
                if ($tussenvoegsel != "")
                {
                    $tussen = " " . $tussenvoegsel . " ";
                }
                $username = $voornaam . $tussen . $achternaam;



                if ($stmt->num_rows == 1)
                { // If the user exists
                    // Check blocked
                    if ($blocked == "1")
                    {
                        return 'Deze acount is geblokkeerd, neem contact met ons op.';
                    }

                    // We check if the account is locked from too many login attempts
                    if ($this->_checkBrute($user_id, $db_accounts) == true)
                    {
                        // Account is locked
                        // Send an email to user saying their account is locked
                        return "Te vaak fout ingelogd,<br />uw account is voor " . $this->blockout_time . " minuten geblokkerd.";
                    }
                    else
                    {
                        if ($db_password == $password && $verified == 1)
                        {
                            // Password is correct!, update lastLogin
                            if ($stmt = $db_accounts->prepare("UPDATE accounts SET date_lastLogin=? WHERE account_id=?"))
                            {
                                $lastlogin = date("Y-m-d H:i:s");

                                $stmt->bind_param('ss', $lastlogin, $user_id); // Bind "$email" to parameter.
                                $stmt->execute();
                                $stmt->close();
                            }

                            $ip_address = $_SERVER['REMOTE_ADDR']; // Get the IP address of the user.
                            $user_browser = $_SERVER['HTTP_USER_AGENT']; // Get the user-agent string of the user.

                            $user_id = preg_replace("/[^0-9]+/", "", $user_id); // XSS protection as we might print this value
                            $_SESSION['user_id'] = $user_id;
                            $username = $username; // XSS protection as we might print this value
                            $_SESSION['username'] = $username;
                            $_SESSION['login_string'] = hash('sha512', $password . $ip_address . $user_browser);
                            // Login successful.

                            if ($this->MailOnLogin != FALSE)
                            {
                                mail($this->MailOnLogin, 'SECUREPLAY - LOGIN', $username . ' logged in to the secureplay platform..');
                            }
                            return false;
                        }
                        else
                        {
                            // Password is not correct
                            // We record this attempt in the database
                            $now = time();
                            $db_accounts->query("INSERT INTO login_attempts (userID, timestamp) VALUES (" . $user_id . ", " . $now . ")");

                            return "Onbekende gebruikersnaam en/of wachtwoord.";
                        }
                    }
                }
                else
                {
                    return "Onbekende gebruikersnaam en/of wachtwoord.";
                }
            }
            else
            {
                return 'SQL FAIL! ' . mysqli_error($db_accounts);
            }
            return "Onbekende fout!";
        }


        return false;
    }

    private function _checkBrute($user_id, $db_accounts)
    {
        // Get timestamp of current time
        $now = time();
        // All login attempts are counted from the past 2 hours.
        $valid_attempts = $now - ($this->blockout_time * 60);

        if ($stmt = $db_accounts->prepare("SELECT timestamp FROM login_attempts WHERE userID = ? AND timestamp > $valid_attempts"))
        {
            $stmt->bind_param('i', $user_id);
            // Execute the prepared query.
            $stmt->execute();
            $stmt->store_result();
            // If there has been more than 5 failed logins
            if ($stmt->num_rows > $this->max_login_fails)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            return true;
        }
    }

    // Login Check if user is logged in correctly
    private function _login_check()
    {
        // Database variables
        $db_accounts = mysqli_connect($this->mySQL_accounts_host, $this->mySQL_accounts_username, $this->mySQL_accounts_password, $this->mySQL_accounts_database);

        // Check if all session variables are set
        if (isset($_SESSION['user_id'], $_SESSION['username'], $_SESSION['login_string']))
        {
            $user_id = $_SESSION['user_id'];
            $login_string = $_SESSION['login_string'];
            $username = $_SESSION['username'];
            $ip_address = $_SERVER['REMOTE_ADDR']; // Get the IP address of the user.
            $user_browser = $_SERVER['HTTP_USER_AGENT']; // Get the user-agent string of the user.

            if ($stmt = $db_accounts->prepare("SELECT login_password FROM accounts WHERE account_id = ? LIMIT 1"))
            {
                $stmt->bind_param('i', $user_id); // Bind "$user_id" to parameter.
                $stmt->execute(); // Execute the prepared query.
                $stmt->store_result();

                if ($stmt->num_rows == 1)
                { // If the user exists
                    $stmt->bind_result($password); // get variables from result.
                    $stmt->fetch();
                    $login_check = hash('sha512', $password . $ip_address . $user_browser);
                    if ($login_check == $login_string)
                    {
                        // Logged In!!!!
                        return $user_id;
                    }
                    else
                    {
                        // Not logged in
                        return false;
                    }
                }
                else
                {
                    // Not logged in
                    return false;
                }
            }
            else
            {
                // Not logged in
                //die("f3");
                return false;
            }
        }
        else
        {
            // Not logged in
            return false;
        }
    }

}

secured_page

<?php
require_once 'assets/class.Firewizz.Security.php';

if (!isset($SECURITY))
{
    $SECURITY = new Firewizz\Security();
}

// Check if user is logged in or redirect to login page;
$SECURITY->BORDER_PATROL(true, true);


// CONTENT bla bla

?>

getPDF.php

<?php
// Requires
require_once 'assets/class.FirePDF.php';
require_once 'assets/class.Firewizz.Security.php';
$SECURITY = new \Firewizz\Security();
$SECURITY->Start_Secure_Session();

// Html file to scrape, if this works replace with referer so the page that does the request gets printed.(prepend by security so it can only be done from securePlay
$html_file = 'http://www.website.nl/?p=overzichten&sort=someSort&s=67';

// Output pdf filename
$pdf_fileName = 'Test_Pdf.pdf';

/*
 * cURL part
 */

// create curl resource
$ch = curl_init();

// set source url
curl_setopt($ch, CURLOPT_URL, $html_file);

// set cookies
$cookiesIn = "user_id=" . $_SESSION['user_id'] . "; username=" . $_SESSION['username'] . "; login_string=" . $_SESSION['login_string'] . ";";

// set cURL Options
$tmp = tempnam("/tmp", "CURLCOOKIE");
if ($tmp === FALSE)
{
    die('Could not generate a temporary cookie jar.');
}

$options = array(
    CURLOPT_RETURNTRANSFER => true, // return web page
    //CURLOPT_HEADER => true, //return headers in addition to content
    CURLOPT_ENCODING => "", // handle all encodings
    CURLOPT_AUTOREFERER => true, // set referer on redirect
    CURLOPT_CONNECTTIMEOUT => 120, // timeout on connect
    CURLOPT_TIMEOUT => 120, // timeout on response
    CURLOPT_MAXREDIRS => 10, // stop after 10 redirects
    CURLINFO_HEADER_OUT => true,
    CURLOPT_SSL_VERIFYPEER => false, // Disabled SSL Cert checks
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_COOKIEJAR => $tmp,
    //CURLOPT_COOKIEFILE => $tmp,
    CURLOPT_COOKIE => $cookiesIn
);

// $output contains the output string
curl_setopt_array($ch, $options);
$output = curl_exec($ch);

// close curl resource to free up system resources
curl_close($ch);

// output the cURL
echo $output;
?>

How we test

Current testing is done by logging the user in and going to the correct page we want to get with cURL and verifying he sees the page(which works). Now we run the getPDF.php page in a new tab. in which we see a blank page due to the security failure. if we add echo "session data:" . $_SESSION["login_string"]; in the security script we see the variables in the $_SESSION is blank. When we paste the same line in the getPDF.php we see it is being set there. So we know for a fact is has not been transferred by cURL.

Some short information.

  • So with above code we get a blank page;
  • $_SESSION data not send;
  • Pretty sure cookies not send either;
  • Tried various cURL setups, none with success all the same;
  • Would be perfect if ALL $_SESSION AND $_COOKIE data is passed;
  • Tried everything said in comments or answers.
  • 写回答
  • 好问题 提建议
  • 关注问题
  • 收藏
  • 邀请回答

3条回答 默认 最新

  • doukui2011 2016-02-20 10:01
    已采纳

    Ok it is solved

    After a lot of research.

    Cookie data is passed but that does not make it session data.. This was fixed using the following method:

    private function Cookie2Session($name)
    {
        if (filter_input(INPUT_COOKIE, $name))
        {
            $_SESSION[$name] = filter_input(INPUT_COOKIE, $name);
        }
    }
    
    // following lines put within the BORDER_PATROL Method
    if (filter_input(INPUT_COOKIE, 'pdfCurl'))
    {
        $this->Cookie2Session('user_id');
        $this->Cookie2Session('username');
        $this->Cookie2Session('login_string');
        $this->Cookie2Session('REMOTE_ADDR');
        $this->Cookie2Session('HTTP_USER_AGENT');
        $_SESSION['new_session'] = "true";
    }
    

    Small alteration to the method _login_check()

    // Login Check if user is logged in correctly
    private function _login_check()
    {
        // Database variables
        $db_accounts = mysqli_connect($this->mySQL_accounts_host, $this->mySQL_accounts_username, $this->mySQL_accounts_password, $this->mySQL_accounts_database);
    
        // Check if all session variables are set
        if (isset($_SESSION['user_id'], $_SESSION['username'], $_SESSION['login_string']))
        {
            $user_id = $_SESSION['user_id'];
            $login_string = $_SESSION['login_string'];
            $username = $_SESSION['username'];
            $ip_address = $_SERVER['REMOTE_ADDR']; // Get the IP address of the user.
            $user_browser = $_SERVER['HTTP_USER_AGENT']; // Get the user-agent string of the user.
    
    // =====>> add this code, because cURL req comes from server. <<=====
            if (isset($_SESSION["REMOTE_ADDR"]) && ($_SERVER['REMOTE_ADDR'] == $_SERVER['SERVER_ADDR']))
            {
                $ip_address = $_SESSION["REMOTE_ADDR"];
            }
    
    // {rest of code}
    

    Small updates to the getPHP.php file:

    <?php
    // Requires
    require_once 'assets/class.FirePDF.php';
    require_once 'assets/class.Firewizz.Security.php';
    $SECURITY = new \Firewizz\Security();
    $SECURITY->Start_Secure_Session();
    
    // Html file to scrape, if this works replace with referer so the page that does the request gets printed.(prepend by security so it can only be done from securePlay
    $html_file = 'http://www.secureplay.nl/?p=overzichten&sort=SpeelplaatsInspecties&s=67';
    
    // Output pdf filename
    $pdf_fileName = 'Test_Pdf.pdf';
    
    /*
     * cURL part
     */
    
    // create curl resource
    $ch = curl_init();
    
    // set source url
    curl_setopt($ch, CURLOPT_URL, $html_file);
    
    // set cookies
    $cookiesIn = "user_id=" . $_SESSION['user_id'] . "; username=" . $_SESSION['username'] . "; login_string=" . $_SESSION['login_string'] . "; pdfCurl=true; REMOTE_ADDR=" . $_SERVER['REMOTE_ADDR'] . "; HTTP_USER_AGENT=" . $_SERVER['HTTP_USER_AGENT'];
    $agent = $_SERVER['HTTP_USER_AGENT'];
    
    // set cURL Options
    $tmp = tempnam("/tmp", "CURLCOOKIE");
    if ($tmp === FALSE)
    {
        die('Could not generate a temporary cookie jar.');
    }
    
    $options = array(
        CURLOPT_RETURNTRANSFER => true, // return web page
        //CURLOPT_HEADER => true, //return headers in addition to content
        CURLOPT_ENCODING => "", // handle all encodings
        CURLOPT_AUTOREFERER => true, // set referer on redirect
        CURLOPT_CONNECTTIMEOUT => 120, // timeout on connect
        CURLOPT_TIMEOUT => 120, // timeout on response
        CURLOPT_MAXREDIRS => 10, // stop after 10 redirects
        CURLINFO_HEADER_OUT => true,
        CURLOPT_SSL_VERIFYPEER => false, // Disabled SSL Cert checks
        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
        CURLOPT_COOKIEJAR => $tmp,
        //CURLOPT_COOKIEFILE => $tmp,
        CURLOPT_COOKIE => $cookiesIn,
        CURLOPT_USERAGENT => $agent
    );
    
    // $output contains the output string
    curl_setopt_array($ch, $options);
    $output = curl_exec($ch);
    
    // close curl resource to free up system resources
    curl_close($ch);
    
    // output the cURL
    echo $output;
    ?>
    

    With the above knowledge you can totally use cURL to visit a secure page with current session data with only minor consessions in your security.

    已采纳该答案
    评论
    解决 无用
    打赏 举报
  • doulu1020 2016-02-17 16:12

    So your $cookiesIn needs to have your cookies defined. I'll make an example based on your code snippets:

    $cookiesIn = "user_id=" . $_SESSION['user_id'] . "; username=" . $_SESSION['username'] . "; login_string=" . $_SESSION['login_string'] . ";";
    

    Try setting that in your pdfCreator page. Replace $cookiesIn = ""; with the line above and see if that gives you a different result.

    Also, here's a great reference for the cURL option cookie:

    https://curl.haxx.se/libcurl/c/CURLOPT_COOKIE.html

    If you want all cookies to just be sent instead of designating them, use this code:

    $tmp = tempnam("/tmp", "CURLCOOKIE");
    if($tmp === FALSE) die('Could not generate a temporary cookie jar.');
    
    $options = array(
        CURLOPT_RETURNTRANSFER => true, // return web page
        //CURLOPT_HEADER => true, //return headers in addition to content
        CURLOPT_ENCODING => "", // handle all encodings
        CURLOPT_AUTOREFERER => true, // set referer on redirect
        CURLOPT_CONNECTTIMEOUT => 120, // timeout on connect
        CURLOPT_TIMEOUT => 120, // timeout on response
        CURLOPT_MAXREDIRS => 10, // stop after 10 redirects
        CURLINFO_HEADER_OUT => true,
        CURLOPT_SSL_VERIFYPEER => false, // Disabled SSL Cert checks
        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
        CURLOPT_COOKIEJAR => $tmp,
        CURLOPT_COOKIEFILE => $tmp,
    );
    

    This code will dump all current know cookies for use in cURL, with the COOKIEJAR option. Then, when we designate COOKIEFILE, we're designating where cURL should look to include cookies with the request.

    That said, I've gotten rid of the $cookiesIn reference as it should not be needed if you use the code above.

    评论
    解决 无用
    打赏 举报
  • douchuza8908 2016-02-20 10:19

    In this case, provided the session control algorithm is sound, you simply want to change the format the page is sent in.

    Using cURL to re-fetch the page is one way to do this, but it looks like a XY problem; you don't actually want to use cURL, you want to control the output format, either HTML or PDF.

    One viable option would be to reload the page after adding a specific parameter which will be injected in the page context and modify the output function. For example you could wrap the whole page in a output buffering bubble:

    // Security checks as usual, then:
    
    if (array_key_exists('output', $_GET)) {
        $format = $_GET['output']; // e.g. "pdf"
        // We could check whether the response handler has a printAs<FORMAT> method
        switch ($format) {
            case 'pdf': $outputFn = 'printAsPDF'; break;
            default:
                throw new \Exception("Output in {$format} format not supported");
        }
        ob_start($output);
    }
    // Page is generated normally
    

    The 'printAsPDF' output will receive the page contents, and would use something like dompdf or wkhtml2pdf to format it as a PDF file, add the appropriate Content-Type headers, and return the formatted PDF.

    Security stays the same, and the modification can actually be implemented at the request decoding stage. A state variable with the currently used output format may be made accessible to other objects, which empowers them to behave differently depending on the situation (for example, a generateMenu() function might choose to immediately return instead of showing something which wouldn't make sense in a PDF).

    评论
    解决 无用
    打赏 举报

相关推荐 更多相似问题