【问题标题】:How to get and post information in a single cURL request?如何在单个 cURL 请求中获取和发布信息?
【发布时间】:2019-10-26 21:33:55
【问题描述】:

是否可以在同一个cURL 请求中获取inputvaluepost 信息?

原因: 我正在尝试使用 cURL 登录 here,但是,登录表单会在名为 form_keyinputvalue 中生成一个唯一密钥。所以,我想先获取该值,然后发布用户名和密码以成功登录。

PHP(不工作,给出一个空白页面,源代码中没有任何内容):

$ch2 = curl_init();
curl_setopt($ch2, CURLOPT_URL, "https://b2b.chiemsee.com/customer/account/login/");
curl_setopt($ch2, CURLOPT_FOLLOWLOCATION, true); // to allow redirections
//curl_setopt($ch2, CURLOPT_SSL_VERIFYPEER, FALSE); // to avoid error
curl_setopt($ch2, CURLOPT_POST, true); // to send info
curl_setopt($ch2, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch2, CURLOPT_COOKIEJAR, 'cookie.txt'); // to save cookie data for login
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true); // to get the html
$response2 = curl_exec($ch2);
curl_close($ch2);

$html = new simple_html_dom();
$html->load($response2);

$val = $html->find('input[name=form_key]');
$form_key = $val[0]->value;

$data = array(
    'form_key' => $form_key,
    'login[username]' => 'myusername',
    'login[password]' => 'mypassword',
    'send' => '',
);

附: 当我手动登录并检查浏览器控制台 -> 网络 -> 帖子 -> 标题/参数时,我得到以下信息:-

form_key: viiRqZigH0YPC9wu
login[username]: myusername
login[password]: mypassword
send: 

更新。 两个单独的 cURL 请求(现在仍在工作):

include('simple_html_dom.php');

$ch2 = curl_init();
curl_setopt($ch2, CURLOPT_URL, "https://b2b.chiemsee.com/customer/account/login/");
curl_setopt($ch2, CURLOPT_FOLLOWLOCATION, true); // to allow redirections
curl_setopt($ch2, CURLOPT_COOKIEJAR, 'cookie.txt'); // to save cookie data for login
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true); // to get the html
$response2 = curl_exec($ch2);
curl_close($ch2);

$html = new simple_html_dom();
$html->load($response2);

$val = $html->find('input[name=form_key]');
$form_key = $val[0]->value;

$data = array(
    'form_key' => $form_key,
    'login[username]' => 'myusername',
    'login[password]' => 'mypassword',
    'send' => 'Anmelden'
);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://b2b.chiemsee.com/customer/account/login/");
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // to allow redirections
//curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // to avoid error
curl_setopt($ch, CURLOPT_POST, true); // to send info
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookie.txt'); // to read data
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // to get the html
$response = curl_exec($ch);
if (curl_error($ch)) {
    $error_msg = curl_error($ch);
    var_dump($error_msg);
    exit;
}
curl_close($ch);
echo $response;

【问题讨论】:

  • CURLOPT_COOKIEJAR 中的注释 请注意 libcurl 不会从 cookie jar 中读取任何 cookie。如果你想从文件中读取cookies,使用CURLOPT_COOKIEFILE. 你需要both。您的第一个请求会将 cookie 写入 cookie jar(因此需要 CURLOPT_COOKIEJAR),第二个请求将需要使用 CURLOPT_COOKIEFILE 从 Jar 中读取 cookie,以确保使用相同的会话。这是必要的,因为 CSRF 保护令牌与会话 cookie 相关联。
  • @apokryfos 好的,但我是在两个请求中使用CURLOPT_COOKIEJAR 还是只在第一个请求中使用?因为在第二个请求中我们发送用户名和密码。
  • 您使用的第一个请求CURLOPT_COOKIEJAR 这将存储服务器发送的cookie。在第二个请求中,您同时使用CURLOPT_COOKIEFILECURLOPT_COOKIEJAR,这会将cookies 发送回服务器,然后保存来自服务器的任何新的/修改的cookies。然后,服务器将使用它接收到的会话 cookie 交叉引用表单密钥,以确保它来自同一个人。
  • @apokryfos 我试过了,但它不起作用。代码在帖子中更新。
  • 该页面表单中的登录 url 是 https://b2b.chiemsee.com/customer/account/loginPost/ 。你好像打错人了

标签: php json parsing curl dom


【解决方案1】:

你问的是不可能的。不是因为 cURL 或 PHP 的限制,而是因为因果关系。考虑正在执行的逻辑步骤集。为了发送登录请求,您必须首先知道form_key。要知道form_key,您必须先请求登录页面。

简单地说,你不能利用你还没有的信息。

  • 发出第一个 HTTP 请求以获取表单信息。 (特别是您需要的 form_key 值。)
  • 发出第二个 HTTP 请求以发送登录信息,包括您从第一个请求中获取的数据。

没有理由尝试一步完成。

【讨论】:

  • 但是如果我在两个单独的请求中执行此操作,那么 form_key 将会改变,因为每次加载页面时 'form_key' 都会发生变化。
  • @Grey-lover:你的假设不正确。如果您重新请求登录页面,form_key 会更改,是的。所以...不要重新请求登录页面。您的第一个请求是获取登录页面的 GET,您的第二个请求是用于登录的 POST。您只是使用 cURL 来准确复制 Web 浏览器正在执行的操作。
  • 遵循此方法,但它不适用于两个单独的请求。使用新代码更新帖子。
  • @Grey-lover:定义“没用”。它以什么具体方式失败?是时候进行一些调试了。第一个 HTTP 请求是否返回登录页面数据?您是否成功地从该数据中获得了 form_key 值?是否发出了第二个 HTTP 请求?它包含哪些数据?服务器的响应是什么?您可以使用 Fiddler 之类的工具来监控来自代码外部的 HTTP 请求,从而观察完整的请求/响应数据。
  • @Grey-lover:还请记住,您开始偏离最初提出的问题。您曾特别询问是否可以发出一个包含从同一请求接收到的信息的 HTTP 请求。答案是否定的。现在,您在发出两个 HTTP 请求时寻求调试帮助。这是一个非常不同的问题。从根本上改变问题的性质会使现有答案无效,并使整个帖子令人困惑且对未来的读者没有帮助。
【解决方案2】:

所以对正在发生的事情进行了一些介绍。

form_key 似乎被用作 CSRF 保护的一种形式,特别是它是 synchronizer token

简而言之,用户访问网页,网页为用户创建会话并生成唯一令牌。然后,服务器将该唯一令牌作为隐藏字段附加到表单。当用户提交该表单时,它会与该隐藏字段一起提交,并且服务器可以交叉引用收到的令牌与发送的令牌相同。

然而,关键部分是服务器需要知道用户是谁,这是通过会话完成的。会话通过会话 cookie 维护,这就是为什么需要会话 cookie。

要正确模拟真实用户,您需要存储服务器在首次访问时发送给您的 cookie,这是使用 CURLOPT_COOKIEJAR 完成的:

$ch2 = curl_init();
curl_setopt($ch2, CURLOPT_URL, "https://b2b.chiemsee.com/customer/account/login/");
curl_setopt($ch2, CURLOPT_FOLLOWLOCATION, true); // to allow redirections
//curl_setopt($ch2, CURLOPT_SSL_VERIFYPEER, FALSE); // to avoid error
curl_setopt($ch2, CURLOPT_POST, true); // to send info
curl_setopt($ch2, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch2, CURLOPT_COOKIEJAR, 'cookie.txt'); // to save session cookie
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true); // to get the html
$response2 = curl_exec($ch2);
curl_close($ch2);

完成此操作并通过抓取页面检索 CSRF 令牌后,您需要将其连同相应的 cookie 一起提交:

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://b2b.chiemsee.com/customer/account/loginPost/"); //Make sure you have the correct URL
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // to allow redirections
//curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // to avoid error
curl_setopt($ch, CURLOPT_POST, true); // to send info
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookie.txt'); // to read cookie data
curl_setopt($ch2, CURLOPT_COOKIEJAR, 'cookie.txt'); // optional, this will update existing cookies and add new ones if needed.
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // to get the html
$response = curl_exec($ch);
if (curl_error($ch)) {
    $error_msg = curl_error($ch);
    var_dump($error_msg);
    exit;
}
curl_close($ch);
echo $response;

这应该允许服务器首先加载创建 CSRF 令牌的正确会话,然后验证您发送的令牌。

作为旁注:令牌的原因很简单。如果我制作的网页诱使用户直接发布到另一个网页,则此令牌是我永远无法访问的数据,因为它仅直接与用户共享,因此第 3 方无法访问它。它可能会使像您这样的自动化更难实现,但它对用户安全非常有效。

【讨论】:

  • 您好,非常感谢,但现在我面临一个新问题,即成功登录后导航到另一个页面。这也可能是关于饼干的吗?你介意看看吗? stackoverflow.com/questions/56573969/…
猜你喜欢
  • 1970-01-01
  • 2013-06-10
  • 1970-01-01
  • 2018-06-09
  • 1970-01-01
  • 2016-10-09
  • 2021-05-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多