O comando Openssl s_client sempre diz 400 Solicitação incorreta

10

Estou tentando testar um servidor que está funcionando normalmente no navegador da web, com a opção openssl s_client, conectando-o diretamente usando o openssl retorna a 400 Solicitação inválida:

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:)

Importante: Eu já tentei colocar o cabeçalho Host:, o fato é que, quando executo GET, o erro ocorre imediatamente, não me deixando chance de incluir mais cabeçalhos. Substitua example.com pelo meu host ...

Luciano Andress Martini
fonte
1
Eu costumo echo: echo -e "GET / HTTP/1.1\r\nHost: example.com.br\r\n\r\n" | openssl s_client .... O \r\né significativo porque é isso que o padrão HTTP diz para fazer. Dois pares de CRLF no final da solicitação também são significativos porque é isso que o padrão diz para fazer. Veja também Como você canaliza "eco" para "openssl"?
Diz DONE, mas nenhuma resposta para o site, isso é normal? Note que eu não posso escrever o cabeçalho Host: no formulário que eu pedi, isso me dá o erro no final do get.
Luciano Andress Martini
Estou supondo (e é apenas um palpite), mas você não está fornecendo o nome correto do documento; ou você não está fornecendo um cookie ou token de acesso. O servidor recebe suas solicitações e erros com um código de erro 4xx para indicar um erro do cliente. Você pode precisar GET /index.html ...ou pode definir um cookie. Você provavelmente deve tentar com curlou wget, e postar o pleno pedido e resposta, incluindo o erro. Caso contrário, você precisará fornecer um nome e um URL reais do servidor para que possamos executar os testes.
Eu sei o nome certo para a URL como eu configurei o servidor, e o estranho é que ele está funcionando no navegador da Web, é muito estranho não querer trabalhar usando o openssl, mesmo se eu especificar o nome de domínio correto no Host: cabeçalho. O erro 500 é muito provável que estou enviando dados em texto sem formatação (usando telnet, por exemplo), mas o openssl está sendo usado ... Acho que vou desistir .... Não é tão importante, é só porque vejo um exemplo de como telnetar um site ssl e deseja experimentá-lo, mas não está indo bem.
Luciano Andress Martini
"Acho que vou desistir ..." - Se você vai se aposentar, exclua a pergunta. As perguntas e respostas não serão concluídas e a pergunta nunca terá uma resposta aceita. Nesse estado, isso pode causar problemas para futuros visitantes. Se precisar de ajuda para excluir a pergunta, sinalize-a para obter atenção do moderador.

Respostas:

19

De acordo com https://bz.apache.org/bugzilla/show_bug.cgi?id=60695, meu comando era:

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

onde -crlf significa, de acordo com a ajuda do comando openssl,

-crlf - converte LF do terminal em CRLF

Depois, pude inserir comandos com várias linhas e nenhum "pedido inválido" como resposta após a primeira linha de comando.

Wei He
fonte
Agora é melhor, mas não funciona quando tento especificar um host, apenas se eu fizer uma simples obtenção.
Luciano Andress Martini
4

OK tinha a mesma coisa e demorou um pouco para descobrir.

Não consigo encontrar uma maneira de enviar várias linhas na solicitação ao usar s_client interativamente. Ele sempre envia a solicitação imediatamente assim que você entra na primeira linha. Se alguém souber como contornar isso, entre em contato!

Edit : Eu vejo Wei Ele postou o caminho para fazer isso - use a -crlfbandeira, mas deixando esta resposta aqui como um método alternativo.

Enquanto isso, como jww sugeriu, você deve usar echopara isso:

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

O próximo problema é que, por padrão, o openssl fecha a conexão quando o arquivo de entrada é fechado. O que acontece imediatamente quando se usa echoassim. Então você não tem tempo para ver a resposta e, em vez disso, apenas vê a saída DONE! :-(

Você pode adicionar um sleepao comando echo para contornar isso (observe que os colchetes são importantes):

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

Ou, melhor que isso, você pode usar a -ign_eofopção para deixar a conexão aberta:

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

Ou melhor ainda, se você está preocupado apenas com as respostas HTTP, use a -quiteopção que oculta a maior parte do ruído TLS e também define a opção -ign_eof para você:

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

Pelo que posso ver, é provável que o 400 Bad Request esteja relacionado ao uso de HTTP / 1.1 na sua linha GET.

Você adicionou um cabeçalho "Host:" após a solicitação GET? O RFC afirma que, para HTTP / 1.1, é necessário um cabeçalho Host:

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

19.6.1.1 Alterações para simplificar servidores Web com hospedagem múltipla e conservar endereços IP

Os requisitos que clientes e servidores suportam o cabeçalho de solicitação de host, relatam um erro se o cabeçalho de solicitação de host (seção 14.23) estiver ausente de uma solicitação HTTP / 1.1 e aceitam URIs absolutos (seção 5.1.2) estão entre os mais importantes mudanças definidas por esta especificação.

elem103
fonte
2

Você pode emitir uma solicitação GET com o 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

Observe que você também pode usar "HTTP / 2", mas tenha cuidado porque alguns servidores (por exemplo, github.com) não são compatíveis.

Steven Penny
fonte