Команда Openssl s_client всегда говорит 400 Bad Request

10

Я пытаюсь протестировать сервер, который нормально работает в веб-браузере, с опцией openssl s_client, подключение его напрямую с помощью openssl возвращает 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:)

Важно: я уже пытался поместить заголовок Host: дело в том, что когда я запускаю GET, сразу же возникает ошибка, и у меня нет шансов включить больше заголовков. Замените example.com моим хостом ...

Лучано Андресс Мартини
источник
1
Я обычно echo: echo -e "GET / HTTP/1.1\r\nHost: example.com.br\r\n\r\n" | openssl s_client .... Это \r\nважно, потому что так говорит стандарт HTTP. Две пары CRLF в конце запроса также важны, потому что это то, что говорит стандарт. Также посмотрите, как вы отправляете «echo» в «openssl»?
Там написано «СДЕЛАНО», но нет ответа для веб-сайта, это нормально? Обратите внимание, что я не могу написать заголовок Host: в форме, которую я спросил, это дает мне ошибку в конце получения.
Лучано Андресс Мартини
Я предполагаю (и это только предположение), но вы не указали правильное имя документа; или вы не предоставляете куки или токен доступа. Сервер получает ваши запросы, а затем ошибки с кодом ошибки 4xx, указывающим на ошибку клиента. Вам может понадобиться GET /index.html ...или вам может понадобиться установить cookie. Вероятно, вам следует попробовать с помощью curlили wgetи опубликовать полный запрос и ответ, включая ошибку. В противном случае вы должны предоставить реальное имя сервера и URL, чтобы мы могли запустить тесты.
Я знаю правильное имя для URL, так как я настроил сервер, и странно то, что он работает в веб-браузере, очень странно, что я не хочу работать с openssl, даже если я укажу правильное доменное имя на хосте: заголовок. Ошибка 500 очень вероятно, что я отправляю данные в виде простого текста (например, используя telnet), но openssl уже используется ... Я думаю, что я просто сдамся ... Не так важно, просто потому, что я вижу пример того, как telnet ssl-сайт, и хотите попробовать, но это не очень хорошо.
Лучано Андресс Мартини
«Думаю, я просто сдамся ...» - если вы собираетесь уйти в отставку, то, пожалуйста, удалите вопрос. Вопросы и ответы не будут завершены, и у вопроса никогда не будет принятого ответа. В таком состоянии это может вызвать проблемы у будущих посетителей. Если вам нужна помощь в удалении вопроса, пометьте его модератором.

Ответы:

19

Согласно https://bz.apache.org/bugzilla/show_bug.cgi?id=60695 моя команда была:

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

где -crlf означает, в соответствии с помощью команды openssl,

-crlf - конвертировать LF из терминала в CRLF

Тогда я мог бы вводить многострочные команды и не получать «плохой запрос» в качестве ответа после первой командной строки.

Вэй Хе
источник
Лучше сейчас, но не работает, когда я пытаюсь указать хост, только если я делаю простой get.
Лучано Андресс Мартини
4

Хорошо, у меня было то же самое, и потребовалось время, чтобы разобраться.

Я не могу найти способ отправить несколько строк в запросе при использовании s_client в интерактивном режиме. Он всегда отправляет запрос сразу же, как только вы ввели первую строку. Если кто-то знает, как обойти это, пожалуйста, дайте мне знать!

Редактировать : я вижу, Вэй Он опубликовал способ сделать это - использовать -crlfфлаг, но оставить этот ответ здесь в качестве альтернативного метода.

В то же время, как предложил jww, вы должны использовать echoдля этого:

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

Следующая проблема заключается в том, что по умолчанию openssl закрывает соединение при закрытии входного файла. Что делает сразу при использовании, echoкак это. Таким образом, у вас нет времени, чтобы увидеть ответ, а вместо этого просто посмотреть на готово! :-(

Вы можете добавить sleepкоманду echo, чтобы обойти это (обратите внимание, что скобки важны):

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

Или, что еще лучше, вы можете использовать -ign_eofопцию, чтобы оставить соединение открытым:

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

Или, что еще лучше, если вас интересуют только ответы HTTP, используйте -quiteпараметр, который скрывает большую часть шума TLS, а также устанавливает для вас этот параметр -ign_eof:

echo -e "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n" | openssl s_client -quiet ...
Барри Поллард
источник
3

Вы можете отправить запрос GET с помощью 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

Обратите внимание, что вы также можете использовать «HTTP / 2», но будьте осторожны, потому что некоторые серверы (например, github.com) не поддерживают его.

Стивен Пенни
источник
2

Из того, что я вижу, 400 Bad Request, скорее всего, связано с использованием HTTP / 1.1 в вашей строке GET.

Вы добавили заголовок "Host:" после запроса GET? RFC утверждает, что для HTTP / 1.1 требуется заголовок Host:

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

19.6.1.1. Изменения в упрощении многодомных веб-серверов и сохранении IP-адресов

Требования о том, что клиенты и серверы поддерживают заголовок запроса Host, сообщают об ошибке, если в запросе HTTP / 1.1 отсутствует заголовок запроса Host (раздел 14.23), и принимают абсолютные URI (раздел 5.1.2). изменения, определенные в этой спецификации.

elem103
источник