La commande openssl s_client dit toujours 400 Bad Request

10

J'essaie de tester un serveur qui fonctionne normalement dans le navigateur Web, avec l'option openssl s_client, le connecter directement en utilisant openssl renvoie la 400 Bad Request:

openssl s_client -servername example.com -connect example.com:443 -tls1
(some information about the certificate)

GET / HTTP/1.1 
(and the error occurs **immediately** - no time to include more headers like Host:)

Important: J'ai déjà essayé de mettre l'en-tête Host:, le problème est que lorsque j'exécute GET, l'erreur se produit immédiatement, ne me laissant aucune chance d'inclure plus d'en-têtes. Remplacez example.com par mon hôte ...

Luciano Andress Martini
la source
1
Je habituellement echo: echo -e "GET / HTTP/1.1\r\nHost: example.com.br\r\n\r\n" | openssl s_client .... C'est \r\nimportant parce que c'est ce que la norme HTTP dit de faire. Deux paires CRLF à la fin de la demande sont également importantes car c'est ce que la norme dit de faire. Voir aussi Comment canaliser "echo" dans "openssl"?
Il indique DONE, mais aucune réponse pour le site Web, est-ce normal? Notez que je ne peux pas écrire l'en-tête Host: dans le formulaire que j'ai demandé, cela me donne l'erreur à la fin du get.
Luciano Andress Martini
Je devine (et c'est juste une supposition), mais vous ne fournissez pas le nom de document correct; ou vous ne fournissez pas de cookie ou de jeton d'accès. Le serveur reçoit vos demandes, puis des erreurs avec un code d'erreur 4xx pour indiquer une erreur client. Vous devrez peut-être GET /index.html ...ou vous devrez peut-être définir un cookie. Vous devriez probablement essayer avec curlou wget, et publier la demande et la réponse complètes , y compris l'erreur. Sinon, vous devez fournir un vrai nom de serveur et une URL afin que nous puissions exécuter les tests.
Je connais le bon nom pour l'URL lors de la configuration du serveur, et ce qui est étrange, c'est qu'il fonctionne sur le navigateur Web, il est très étrange de ne pas vouloir travailler avec openssl même si je spécifie le bon nom de domaine sur l'hôte: entête. L'erreur 500 est très probable que j'envoie des données en texte brut (en utilisant telnet par exemple), mais openssl a été utilisé ... Je pense que je vais simplement abandonner .... N'est pas si important, c'est simplement parce que je vois un exemple de la façon de telnet un site Web ssl, et que vous voulez l'essayer, mais cela ne fonctionne pas bien.
Luciano Andress Martini
"Je pense que je vais simplement abandonner ..." - Si vous allez prendre votre retraite, veuillez supprimer la question. Le Q&A ne se terminera pas et la question n'aura jamais de réponse acceptée. Dans cet état, cela pourrait causer des problèmes aux futurs visiteurs. Si vous avez besoin d'aide pour supprimer la question, signalez-la à l'attention du modérateur.

Réponses:

19

Selon https://bz.apache.org/bugzilla/show_bug.cgi?id=60695 ma commande était:

openssl s_client -crlf -connect www.pgxperts.com:443

où -crlf signifie, selon l'aide de la commande openssl,

-crlf - convertit LF du terminal en CRLF

Ensuite, je pouvais entrer des commandes multilignes et aucune "mauvaise demande" comme réponse après la première ligne de commande.

Wei He
la source
C'est mieux maintenant, mais ne fonctionne pas lorsque j'essaie de spécifier un hôte, uniquement si je fais un simple get.
Luciano Andress Martini
4

OK avait la même chose moi-même et a pris un certain temps pour comprendre.

Je ne trouve pas de moyen d'envoyer plusieurs lignes dans la demande lors de l'utilisation interactive de s_client. Il envoie toujours la demande immédiatement dès que vous avez entré la première ligne. Si quelqu'un sait comment contourner cela, faites-le moi savoir!

Edit : Je vois que Wei He a publié la façon de le faire - utilisez le -crlfdrapeau mais laissez cette réponse ici comme méthode alternative.

En attendant, comme l'a suggéré jww, vous devez utiliser echopour cela:

echo -e "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n" | openssl s_client ...

Le problème suivant est que, par défaut, openssl ferme la connexion lorsque le fichier d'entrée se ferme. Ce qui se fait immédiatement lors de l'utilisation echocomme ceci. Donc, vous n'avez pas le temps de voir la réponse et voyez simplement la sortie DONE! :-(

Vous pouvez ajouter un sleepà la commande echo pour contourner ce problème (notez que les crochets sont importants):

(echo -e "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"; sleep 10) | openssl s_client ...

Ou, mieux que cela, vous pouvez utiliser l' -ign_eofoption pour laisser la connexion ouverte:

echo -e "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n" | openssl s_client -ign_eof ...

Ou mieux encore, si vous ne vous souciez que des réponses HTTP, utilisez l' -quiteoption qui masque la plupart du bruit TLS et définit également cette option -ign_eof pour vous:

echo -e "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n" | openssl s_client -quiet ...
Barry Pollard
la source
3

D'après ce que je peux voir, la 400 Bad Request est probablement liée à l'utilisation de HTTP / 1.1 dans votre ligne GET.

Avez-vous ajouté un en-tête "Host:" après la demande GET? Le RFC indique que pour HTTP / 1.1, un en-tête Host est requis:

https://www.ietf.org/rfc/rfc2616.txt

19.6.1.1 Modifications pour simplifier les serveurs Web multi-hébergés et conserver les adresses IP

Les exigences que les clients et les serveurs prennent en charge l'en-tête de demande Host, signalent une erreur si l'en-tête de requête Host (section 14.23) est manquante dans une requête HTTP / 1.1, et acceptent les URI absolus (section 5.1.2) sont parmi les plus importantes. changements définis par cette spécification.

elem103
la source
2

Vous pouvez émettre une demande GET avec OpenSSL:

openssl s_client -quiet -connect cdn.sstatic.net:443 <<eof
GET /stackexchange/js/universal-login.js HTTP/1.1
Connection: close
Host: cdn.sstatic.net

eof

Notez que vous pouvez également utiliser "HTTP / 2", mais soyez prudent car certains serveurs (par exemple github.com) ne le prennent pas en charge.

Steven Penny
la source