草庐IT

php - 使用 cURL 和安全页面上的当前 session 和 cookie 数据检索网站 HTML 页面

coder 2023-06-14 原文

问题完全修改于:2 月 19 日

我想要的东西(简而言之):

我想获得一个使用 cURL 的 HTML 页面,该页面受用户登录保护(在 cURL 请求时用户已登录并有权访问该页面)。 em>

更详细:

情况是用户在像 index.php?w=2344&y=lalala&x=something 这样的网页上,该网页受到保护(由安全脚本 class.Firewizz.Security.php)。在该页面上有一个“打印为 pdf”按钮。这会将用户发送到 getPDF.php 页面,该页面会查看请求的来源并使用 cURL 获取该页面,并且该输出将作为 PDF 打印发送到浏览器。

但现在我在 getPDF.php 页面中将页面变量设置为静态,这样它就不会检查引荐来源网址,而且我 100% 确定它尝试获取的页面是正确的。

此外,输出只是按原样回显,尚未转换为 PDF,这样就不会干扰问题。

预期输出现在与用户转到该页面时的预期输出相同。除非情况并非如此,否则用户将一无所获。

我们知道什么? 我们知道 $_SESSION 数据没有被发送到 cURL,我知道这是事实,因为我在输出文件上回显了 $_SESSION 数据,说它们是空的。

经过大量尝试,我们仍然没有任何解决方案,仍然没有“$_SESSION”数据。

我不想以任何方式破坏安全脚本,所以解决方案“删除 ini_set('session.use_only_cookies', 1); 不是我要找的。”

根据要求(对于那些致力于帮助的人),我可以发送完整的脚本文件,但我会在下面发布相关的片段。

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_pa​​ge

<?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;
?>

我们如何测试

当前的测试是通过让用户登录并转到我们希望使用 cURL 获得的正确页面并验证他是否看到该页面(有效)来完成的。现在我们在新选项卡中运行 getPDF.php 页面。由于安全故障,我们在其中看到一个空白页面。如果我们添加 echo "session data:"。 $_SESSION["login_string"];在安全脚本中,我们看到 $_SESSION 中的变量是空白的。当我们将同一行粘贴到 getPDF.php 时,我们会看到它已被设置在那里。所以我们知道一个事实是没有被 cURL 转移。

一些简短的信息。

  • 所以通过上面的代码我们得到了一个空白页面;
  • $_SESSION 数据未发送;
  • 很确定 cookie 也不会发送;
  • 尝试了各种 cURL 设置,但都没有成功;
  • 如果传递了所有 $_SESSION 和 $_COOKIE 数据就完美了;
  • 尝试过评论或回答中所说的一切。

最佳答案

好的,解决了

经过大量研究。

Cookie 数据已传递,但不会使其成为 session 数据.. 使用以下方法修复了此问题:

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";
}

_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}

getPHP.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.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;
?>

有了以上知识,您完全可以使用 cURL 访问具有当前 session 数据的安全页面,而您的安全性中只有少量 session 。

关于php - 使用 cURL 和安全页面上的当前 session 和 cookie 数据检索网站 HTML 页面,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35391065/

有关php - 使用 cURL 和安全页面上的当前 session 和 cookie 数据检索网站 HTML 页面的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  5. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  6. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  7. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  8. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  9. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  10. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

随机推荐