如何强制 CURL 要求 http/1.1?或者也许有另一个问题,不确定

2022-08-30 13:41:16

我有一段代码(让我们将其命名为Code A)在一个框架中工作,我想让它在另一个框架中工作。工作代码段使用 CURL 发出成功的 POST 请求,如下所示(请求CURLOPT_VERBOSE 打开):

* Connected to android.clients.google.com (216.58.209.238) port 443 (#0)
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /Applications/MAMP/Library/OpenSSL/cert.pem
    CApath: none
* SSL connection using TLSv1.2 / ECDHE-ECDSA-AES128-GCM-SHA256
* ALPN, server accepted to use http/1.1
* Server certificate:
*  subject: C=US; ST=California; L=Mountain View; O=Google Inc; CN=*.google.com
*  start date: Jan 18 19:17:59 2017 GMT
*  expire date: Apr 12 18:51:00 2017 GMT
*  subjectAltName: host "android.clients.google.com" matched cert's "android.clients.google.com"
*  issuer: C=US; O=Google Inc; CN=Google Internet Authority G2
*  SSL certificate verify ok.
> POST /auth HTTP/1.1
Host: android.clients.google.com
Accept: */*
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Content-Length: 97

这里的http框架(yii2 / httpclient,具体来说)有太多的依赖项,无法将其引入其他项目,因此我尝试在低级别上重新创建它,如下所示(让我们将其命名为代码B):

<?php 
$ch = curl_init();
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'post-data-here');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_URL, 'https://android.clients.google.com/auth');
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-Type: application/x-www-form-urlencoded; charset=UTF-8"]); // just because I'm desperate
curl_setopt($ch, CURLOPT_VERBOSE, true);
$content = curl_exec($ch);

我希望有相同的结果,但这就是我得到的:

* Connected to android.clients.google.com (216.58.209.238) port 443 (#0)
* TLS 1.2 connection using TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
* Server certificate: *.google.com
* Server certificate: Google Internet Authority G2
* Server certificate: GeoTrust Global CA
> POST /auth HTTP/1.1
Host: android.clients.google.com
Accept: */*
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Content-Length: 97
* upload completely sent off: 97 out of 97 bytes
< HTTP/1.1 200 OK
< Content-Type: text/plain; charset=utf-8
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: Mon, 01 Jan 1990 00:00:00 GMT
< Date: Fri, 27 Jan 2017 12:07:12 GMT
< X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
< X-XSS-Protection: 1; mode=block
< Server: GSE
< Alt-Svc: clear
< Accept-Ranges: none
< Vary: Accept-Encoding
< Transfer-Encoding: chunked
<HTML>
<HEAD>
<TITLE>HTTP Version Not Supported</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H1>HTTP Version Not Supported</H1>
<H2>Error 505</H2>
</BODY>
</HTML>

而不是有效的响应,我得到“错误505:HTTP版本不受支持”。我看到的唯一区别是工作代码尝试“ALPN,提供http / 1.1”,而后一个代码不这样做。之后是证书部分,但它从未在代码A中提及过,所以我不确定它做了什么来提供它。

两个版本的代码都运行在同一台服务器上,相同版本的 PHP (5.6) 和 CURL (7.51.0)。详细日志的差异在发送任何数据之前就开始了,所以我想这不是关于任何数据或标头设置不正确。

到目前为止,我尝试过什么(效果很少或根本没有效果):

  1. curl_setopt($ch,CURLOPT_SSL_ENABLE_ALPN,等等) - 不起作用,因为根本没有定义CURLOPT_SSL_ENABLE_ALPN(尽管它必须在这个版本的CURL中,不确定出了什么问题)
  2. curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,随便什么)
  3. curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,随便什么)
  4. curl_setopt($ch,CURLOPT_SSLVERSION,随便什么)
  5. 其他一些绝望的愚蠢的东西,我甚至羞于在这里展示

我试图尽可能深入地学习工作代码,但似乎它没有在简单的HTTP POST上做任何事情。我跟踪了它所做的每一个curl_setopt,似乎只有这些curl_setopt我在代码中使用,没有什么额外的。尽管如此,它的工作原理,而我的代码不起作用。

我尝试使用命令行进行相同的操作:

$ curl https://android.clients.google.com/auth -v --http1.1 -X POST --no-alpn --no-npn --data "copypasted-post-data-from-code-B-and-yes-its-urlencoded"

得到正确的结果:

*   Trying 216.58.209.238...
* TCP_NODELAY set
* Connected to android.clients.google.com (216.58.209.238) port 443 (#0)
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /Applications/MAMP/Library/OpenSSL/cert.pem
  CApath: none
...
> POST /auth HTTP/1.1
> Host: android.clients.google.com
> User-Agent: curl/7.51.0
> Accept: */*
> Content-Length: 97
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 97 out of 97 bytes
< HTTP/1.1 200 OK
< Content-Type: text/plain; charset=utf-8
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: Mon, 01 Jan 1990 00:00:00 GMT
< Date: Fri, 27 Jan 2017 13:22:27 GMT
< X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
< X-XSS-Protection: 1; mode=block
< Server: GSE
< Alt-Svc: clear
< Accept-Ranges: none
< Vary: Accept-Encoding
< Transfer-Encoding: chunked
<
SID=BAD_COOKIE
LSID=BAD_COOKIE
Auth=here-s-the-data-i-need

答案 1

Error 505: HTTP Version Not Supported不是由 curl/libcurl 返回的错误字符串,这听起来像是从与之通信的服务器收到的内容。如果您向我们展示完整的HTTP响应(包括标头),我们可能已经看到了这一点。

所以,你所有玩不同的卷曲选项都是没有收获的,因为卷曲每次都工作得很好。您还可以验证是否使用 curl 命令行工具来攻击您尝试开始工作的主机:

curl https://android.clients.google.com/auth -v --http1.1 -X POST --no-alpn --no-npn

此命令行显示 TLS 和 HTTP“层”都很好。

这里的另一个问题在传入错误数据(不是url编码)时得到了类似的错误。也许你有类似的东西,因为你切换到一个新的框架,你错过了它?


答案 2

好吧,我想通了。

实际上,在代码B中的那段代码之前,有另一个请求使用另一个库(确切地说是Httpful)执行,似乎该请求以某种方式搞砸了事情。我不知道某些事情会影响使用干净的curl_init()执行的请求。

无论如何,当我在有问题的请求之前用低级调用替换所有那些Httpful调用时,一切正常。


推荐