Wie kann man CURL zwingen, nach http/1.1 zu fragen? Oder vielleicht gibt es ein anderes Problem, ich bin mir nicht sicher

Lesezeit: 6 Minuten

Benutzer-Avatar
Andrej

Ich habe ein Stück Code (nennen wir es Code A), das in einem Framework arbeitet, und ich möchte es in einem anderen Framework zum Laufen bringen. Der funktionierende Code macht eine erfolgreiche POST-Anfrage mit CURL wie folgt (Anfrage mit aktiviertem 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

Das http-Framework hier (yii2/httpclient, um genau zu sein) hat zu viele Abhängigkeiten, um es in das andere Projekt zu bringen, also versuche ich, es auf niedriger Ebene wie folgt neu zu erstellen (nennen wir es Code 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);

Ich erwarte, dass das das gleiche Ergebnis hat, aber das ist, was ich bekomme:

* 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>

Und statt einer gültigen Antwort bekomme ich “Error 505: HTTP Version Not Supported”. Der einzige Unterschied, den ich sehe, ist, dass der Arbeitscode versucht, “ALPN, http/1.1 anzubieten”, während der letztere Code dies nicht tut. Und der Zertifikatsteil danach, aber er wird nie in Code A erwähnt, also bin ich mir nicht sicher, was er tut, um ihn bereitzustellen.

Beide Codeversionen laufen auf demselben Server, dieselbe Version von PHP (5.6) und CURL (7.51.0). Der Unterschied im ausführlichen Protokoll beginnt, BEVOR Daten gesendet werden, also denke ich, dass es nicht darum geht, dass Daten oder Header falsch eingestellt sind.

Was ich bisher versucht habe (mit wenig oder keiner Wirkung):

  1. curl_setopt($ch, CURLOPT_SSL_ENABLE_ALPN, was auch immer) – funktioniert nicht, weil CURLOPT_SSL_ENABLE_ALPN überhaupt nicht definiert ist (obwohl es in dieser Version von CURL sein muss, nicht sicher, was falsch ist)
  2. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, was auch immer)
  3. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, was auch immer)
  4. curl_setopt($ch, CURLOPT_SSLVERSION, was auch immer)
  5. einige andere verzweifelte dumme Sachen, für die ich mich sogar schäme, sie hier zu zeigen

Ich habe versucht, den Arbeitscode so tief wie möglich zu lernen, aber es scheint, dass er nichts über den einfachen HTTP-POST ausführt. Ich habe jeden curl_setopt verfolgt, den er macht, und es scheint, dass es nur diese curl_setopt gibt, die ich in meinem Code verwendet habe, nichts Besonderes. Trotzdem funktioniert es und mein Code nicht.

Ich habe versucht, dasselbe über die Befehlszeile zu machen:

$ 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"

Habe das richtige Ergebnis:

*   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

  • Wie ich im vorherigen Abschnitt sehen kann, wird ein SSL-Zertifikat bereitgestellt, aber Sie haben kein Zertifikat bereitgestellt.

    – MA SIDDIQUI

    27. Januar 2017 um 12:55 Uhr

  • Nun ja, das auch, aber ich gebe diesen Zertifikatspfad auch nicht in Code A an. Ich bin mir nicht sicher, was es tut, um es bereitzustellen, und wie ich das wiederhole. Meine Vermutung ist CURLOPT_CAINFO, CURLOPT_CAPATH (hat keine Auswirkung und wird nirgendwo im Arbeitscode verwendet)

    – Andrej

    27. Januar 2017 um 13:05 Uhr

  • Das SSL-Zertifikat ist eine Art Signatur, um eine sichere Verbindung über das TCP-Protokoll herzustellen. Dies ist jedoch nicht obligatorisch, bis der Dienstanbieter eine unsichere Verbindung ablehnt. Ich frage nur, ob Sie ein Problem mit der Antwort haben, nicht mit den Antwortheadern

    – MA SIDDIQUI

    27. Januar 2017 um 13:08 Uhr

  • Die Antwort, die ich mit Code B bekomme, ist

    HTTP-Version nicht unterstützt

    Fehler 505

    das ist das Problem 🙂 Code A liefert die gewünschte Antwort, keinerlei Fehler

    – Andrej

    27. Januar 2017 um 13:11 Uhr


  • definiere es einfach manuell dann ` if(!defined('CURLOPT_SSL_ENABLE_ALPN')){define('CURLOPT_SSL_ENABLE_ALPN',226);} und stellen Sie sicher, dass curl_setopt(_array?) bool(true) zurückgibt

    – Hansenrik

    28. Januar 2017 um 13:17 Uhr


Error 505: HTTP Version Not Supported ist keine Fehlerzeichenfolge, die von curl/libcurl zurückgegeben wird, das klingt wie Inhalt die Sie von dem Server erhalten, mit dem Sie kommunizieren. Wenn Sie uns die vollständige HTTP-Antwort einschließlich Header zeigen würden, hätten wir das wahrscheinlich sehen können.

Ihr Herumspielen mit verschiedenen Curl-Optionen war also umsonst, weil Curl jedes Mal gut funktionierte. Sie können dies auch überprüfen, indem Sie das Curl-Befehlszeilentool für den Host verwenden, den Sie zum Laufen bringen möchten:

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

Diese Befehlszeile zeigt, dass sowohl die TLS- als auch die HTTP-„Ebene“ in Ordnung sind.

Eine andere Frage hier hat einen ähnlichen Fehler erhalten, als sie die falschen Daten (nicht URL-codiert) übergeben hat. Vielleicht haben Sie etwas Ähnliches und aufgrund Ihrer Umstellung auf ein neues Framework haben Sie es verpasst?

  • Ja, Sie haben Recht, der HTTP-Code ist tatsächlich 200 und es scheint, als wäre 505 der Fehler, den ich nur im Inhalt sehe. Es wurde versucht, den tatsächlichen POST von der Befehlszeile aus mit genau derselben Zeichenfolge aus Code B (URL-codiert) zu senden und den gewünschten Inhalt zu erhalten. Ich füge das jetzt der Frage hinzu

    – Andrej

    27. Januar 2017 um 13:24 Uhr

Okay, ich habe es herausgefunden.

Tatsächlich wurde VOR diesem Codeabschnitt in Code B eine weitere Anfrage mit einer weiteren Bibliothek (Httpful, um genau zu sein) ausgeführt, und es scheint, dass diese Anfrage die Dinge irgendwie durcheinander gebracht hat. Ich wusste nicht, dass etwas eine Anfrage beeinflussen kann, die mit einem sauberen curl_init() ausgeführt wird.

Wie auch immer, als ich all diese Httpful-Aufrufe vor der fraglichen Anfrage durch Low-Level-Aufrufe ersetzte, funktionierte alles einwandfrei.

1198120cookie-checkWie kann man CURL zwingen, nach http/1.1 zu fragen? Oder vielleicht gibt es ein anderes Problem, ich bin mir nicht sicher

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy