Home > HTTPS > HTTPS no cliente
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).
| 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.
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.
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.
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 |
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.
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.
| 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).
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:// |
.ini editável: quem.ini.SSL.Required).Manual completo (inglês): src/engine/SSL.md no repositório.