Skip to content
mobius1qwe edited this page Oct 15, 2026 · 5 revisions

Home > HTTPS > HTTPS no cliente

HTTPS no cliente: qual certificado aceitar

Vale para a 1.1 em diante · Delphi e Lazarus · Nível: intermediário

Em uma frase: o TRALClient pode aceitar só o certificado que você espera, pela impressão digital, sem instalar nada na máquina nem no celular.

Servidor com certificado de CA pública (Let's Encrypt, pago)? Não precisa de nada desta página: funciona sozinho. Ela é para o autoassinado: servidor interno, acesso por IP, IP que muda, ou Android (que desde a versão 7 não confia em CA instalada pelo usuário).

As quatro opções

Membro Para que serve
SSL.Pins os certificados aceitos, e de qual servidor
SSL.Required recusa http:// puro, diga o que disser a URL
SSL.Verify o que o próprio motor faz com o certificado
OnValidateServerCert decidir em código, quando a lista não basta

Sem mexer em nenhuma, o cliente se comporta como sempre se comportou.

Pegar a impressão digital

Do arquivo: openssl x509 -in cert.pem -noout -fingerprint -sha256

De um servidor no ar: openssl s_client -connect 192.168.0.11:9988 </dev/null 2>/dev/null | openssl x509 -noout -fingerprint -sha256

Do certificado automático (2.0 🚧): a propriedade Fingerprint.

Cole como vier: com :, espaços, minúsculas. O RAL normaliza. Valor que não é um SHA-256 dá erro na hora de adicionar, não em produção.

Receita 1: um servidor autoassinado

Cliente.BaseURL.Text := 'https://192.168.0.11:9988';
Cliente.SSL.Pins.Add('6542DB04A4778A33BDBDF9EC5C953793D4F73572EA804C145FBB55641735290A');

A partir daí: só aquele certificado é aceito (até um de CA é recusado); o nome e o IP no certificado deixam de importar (trocar o IP não quebra); e http:// passa a ser recusado para esse servidor.

Receita 2: vários servidores, uns com CA e outros autoassinados

Cada linha diz onde vale. Servidor que não tem linha é validado normalmente:

Cliente.SSL.Pins.Text :=
  '192.168.0.11=CD34EF...'#13#10 +     // só nesse host
  '10.0.0.7:8443=90FFEE...'#13#10 +    // nesse host e porta
  '[2001:db8::1]:9988=1234AB...';      // IPv6 entre colchetes
Linha Vale para
impressão qualquer servidor
host=impressão aquele host, qualquer porta
host:porta=impressão aquele host e porta
[ipv6]:porta=impressão IPv6 com porta

Receita 3: trocar o certificado sem parar ninguém

Duas linhas para o mesmo servidor valem as duas. Distribua o cliente com a atual e a nova, troque o certificado no servidor quando quiser, e tire a antiga na versão seguinte.

Receita 4: decidir em código

Com o evento atribuído, só ele decide (nem pin nem motor):

function TForm1.ValidaCert(ASender: TObject; const ACert: TRALCertInfo): boolean;
begin
  if ACert.Host = '192.168.0.11' then
    Result := ACert.Fingerprint = PIN_INTERNO
  else
    Result := ACert.Trusted;  // o resto: validação normal
end;

TRALCertInfo traz Fingerprint, Subject, Issuer, NotBefore, NotAfter, Trusted (o veredito do motor), Error, Host e Port (de quem você chamou). Recusar corta a conexão antes de enviar qualquer byte, token incluído.

SSL.Verify: o que o motor faz sozinho

Valor Significa
svEngine (padrão) o de sempre de cada motor: Indy e fpHTTP não conferem nada; netHTTP e mORMot2 conferem
svAlways liga a conferência onde está desligada
svNever aceita qualquer certificado. Só para teste

svAlways no Windows com Indy ou fpHTTP recusa tudo, até CA pública, porque o OpenSSL deles não tem lista de CAs lá. Prefira um pin.

O que cada motor consegue

Motor Confere por padrão SSL.Pins OnValidateServerCert
Indy não sim sim
fpHTTP não sim sim
mORMot2 com OpenSSL sim sim sim
mORMot2 no Windows (SChannel) sim não: chame OpenSslInitialize (unit mormot.lib.openssl11) não
netHTTP sim só no Windows sim (só pode vetar um certificado bom)
OkHttp 1.2 🚧 sim sim (Android) sim
MsQuic / Kwik 1.2 🚧 sim sim sim

Pinar no Delphi e no Lazarus, no Windows e no Android, com uma configuração só: Indy (com ssleay32.dll e libeay32.dll ao lado do programa).

Quando recusa

Resposta.TransportError = rteCertificate (na chamada com evento). Nunca tenta a próxima BaseURL por causa disso.

Com SSL.Required ou um pin para o servidor, um redirecionamento de https:// para http:// não é seguido: a resposta 3xx volta como veio.

Mensagem Significa
emCertRejected o pin ou o evento recusou
emCertPinUnsupported aquele motor não lê impressão digital naquela plataforma
emCertNotInspectable mORMot2 no SChannel: chame OpenSslInitialize
emCertPinInvalid linha de SSL.Pins mal escrita (avisa ao adicionar)
emCertRequiresTLS SSL.Required ou pin, e a URL é http://

Segurança

  • O pin é mais forte que a validação por CA: só aquele certificado passa.
  • Guarde a impressão no programa (constante), não num .ini editável: quem edita a linha aponta o cliente para outro servidor. Host e porta podem ficar no .ini.
  • O pin não cifra nada sozinho: use HTTPS (SSL.Required).

Manual completo (inglês): src/engine/SSL.md no repositório.

Veja também

Clone this wiki locally