Cliente SSH com o Componente sgcIndy para Delphi

· Componentes

Administração remota de servidores, implantações automatizadas, gerenciamento de configuração e monitoramento de infraestrutura — tudo isso depende de acesso seguro via shell. Seja para executar um único comando em um host remoto, abrir uma sessão de terminal interativo ou configurar um túnel de port forwarding, o SSH é o protocolo que torna tudo isso possível.

O pacote sgcIndy inclui TIdSSHClient — um componente cliente SSH nativo para Delphi que implementa o protocolo SSH-2 com suporte completo a execução de comandos, shells interativos, alocação de pseudo-terminal, port forwarding, keep-alive e algoritmos criptográficos modernos. Sem executáveis SSH externos, sem wrappers de DLL — arquitetura de componente Delphi pura com uma API orientada a eventos.

Este artigo apresenta os principais recursos e fornece exemplos de código Delphi para os casos de uso SSH mais comuns.

Principais Recursos

Execução de Comandos
Execute comandos remotos e capture stdout, stderr e códigos de saída. Método de conveniência em uma linha ou controle completo baseado em canal.
Shell Interativo
Abra sessões de shell interativo com suporte a pseudo-terminal. Envie comandos, receba saída de forma assíncrona e trate o redimensionamento do terminal.
Port Forwarding
Configure túneis TCP/IP diretos e forwarding reverso. Acesse serviços remotos através de túneis SSH criptografados.
Criptografia Moderna
Curve25519, ECDH, AES-GCM, chaves Ed25519. Negociação de algoritmos configurável com padrões seguros prontos para uso.
Múltiplos Métodos de Autenticação
Senha, chave pública (RSA, ECDSA, Ed25519) e autenticação keyboard-interactive. Verificação de host key via callback de evento.
Multi-Canal
Até 10 canais simultâneos por conexão. Execute múltiplos comandos, shells ou túneis ao mesmo tempo em uma única sessão SSH.

Início Rápido — Executar um Comando Remoto

O caso de uso mais simples: conectar, executar um comando, obter a saída e desconectar — tudo em poucas linhas.

var
  oSSH: TIdSSHClient;
  vOutput: string;
begin
  oSSH := TIdSSHClient.Create(nil);
  Try
    oSSH.Host := 'server.example.com';
    oSSH.Port := 22;
    oSSH.Authentication.Username := 'admin';
    oSSH.Authentication.Password := 'secret';
    oSSH.Connect;
    // Execute a command and capture the output
    vOutput := oSSH.Execute('df -h');
    WriteLn(vOutput);
    oSSH.Disconnect;
  Finally
    oSSH.Free;
  End;
end;

Uma linha. O método Execute abre um canal, executa o comando, aguarda o resultado e retorna a saída como string — perfeito para automação via scripts.

Autenticação

Três métodos de autenticação são suportados. Os três estão habilitados por padrão e o cliente negocia automaticamente com o servidor.

Senha

oSSH.Authentication.Username := 'admin';
oSSH.Authentication.Password := 'secret';

Chave Pública

oSSH.Authentication.Username := 'deploy';
oSSH.Authentication.PrivateKeyFile := 'C:\keys\id_ed25519';
oSSH.Authentication.PublicKeyFile := 'C:\keys\id_ed25519.pub';
oSSH.Authentication.Passphrase := 'keypassphrase';

Keyboard-Interactive

Trate prompts de autenticação em múltiplas etapas (MFA, OTP, perguntas de segurança) através do evento OnSSHKeyboardInteractive.

oSSH.OnSSHKeyboardInteractive := OnKeyboardInteractive;
procedure TForm1.OnKeyboardInteractive(Sender: TObject;
  const aName, aInstruction: string;
  aPrompts: TStrings; aEchos: TList; aResponses: TStrings);
begin
  // Respond to each prompt (e.g., "Password:", "OTP:")
  if aPrompts.Count > 0 then
    aResponses.Add('mypassword');
end;

Verificação de Host Key

oSSH.OnSSHHostKey := OnHostKey;
procedure TForm1.OnHostKey(Sender: TObject;
  const aHostKeyType, aFingerprint: string;
  var aAction: TIdSSHHostKeyVerification);
begin
  // Accept or reject based on known fingerprint
  aAction := sshHostKeyAccept;
end;

Execução de Comandos

Duas abordagens para executar comandos remotos: o método de conveniência Execute para casos simples, ou a API baseada em canal para controle total de entrada, saída e status de saída.

Simples: Método Execute

// Execute and get output (30-second timeout by default)
vOutput := oSSH.Execute('ls -la /var/log');
// Custom timeout (10 seconds)
vOutput := oSSH.Execute('cat /etc/hostname', 10000);

Avançado: Execução Baseada em Canal

Para execução assíncrona com tratamento separado de stdout/stderr e rastreamento de status de saída.

// Open a channel and execute a command
var
  vChannelId: Cardinal;
begin
  vChannelId := oSSH.OpenChannel;
  oSSH.RequestExec(vChannelId, 'tar czf /tmp/backup.tar.gz /data');
  // Output arrives via OnSSHChannelData event
  // Exit status arrives via OnSSHChannelExitStatus event
end;
// Handle stdout
procedure TForm1.OnChannelData(Sender: TObject;
  aChannelId: Cardinal; const aData: TIdBytes);
begin
  Memo1.Lines.Add(BytesToString(aData));
end;
// Handle stderr
procedure TForm1.OnChannelExtendedData(Sender: TObject;
  aChannelId: Cardinal; aDataType: Cardinal; const aData: TIdBytes);
begin
  MemoErrors.Lines.Add(BytesToString(aData));
end;
// Handle exit status
procedure TForm1.OnExitStatus(Sender: TObject;
  aChannelId: Cardinal; aExitStatus: Integer);
begin
  WriteLn('Command exited with code: ' + IntToStr(aExitStatus));
end;

Sessões de Shell Interativo

Abra um pseudo-terminal e interaja com um shell remoto — ideal para criar emuladores de terminal SSH ou automatizar fluxos de trabalho CLI interativos.

// Open channel, request PTY, then request shell
var
  vChannelId: Cardinal;
begin
  vChannelId := oSSH.OpenChannel;
  // Request a pseudo-terminal (xterm, 80x24)
  oSSH.RequestPTY(vChannelId, 'xterm', 80, 24);
  // Start the shell
  oSSH.RequestShell(vChannelId);
  // Send commands to the shell
  oSSH.SendChannelData(vChannelId, 'cd /var/log' + #13#10);
  oSSH.SendChannelData(vChannelId, 'tail -f syslog' + #13#10);
end;

Redimensionamento de Terminal & Sinais

// Notify the server of terminal resize
oSSH.SendWindowChange(vChannelId, 120, 40, 0, 0);
// Send Ctrl+C (interrupt signal)
oSSH.SendSignal(vChannelId, 'INT');
// Set an environment variable before running commands
oSSH.SetEnvironmentVariable(vChannelId, 'LANG', 'en_US.UTF-8');
// Signal end of input
oSSH.SendEOF(vChannelId);

Port Forwarding (Túneis SSH)

Crie túneis criptografados para acessar serviços remotos como se fossem locais. Útil para acessar de forma segura bancos de dados, painéis de administração ou APIs internas atrás de firewalls.

Tunelamento TCP/IP Direto (Forward Local)

// Tunnel to a remote database through SSH
var
  vTunnelId: Cardinal;
begin
  vTunnelId := oSSH.OpenDirectTCPIP(
    'db-internal.example.com',  // Remote host
    5432,                        // Remote port (PostgreSQL)
    '127.0.0.1',                 // Originator IP
    0);                           // Originator port
  // Send/receive data through the tunnel
  oSSH.SendChannelData(vTunnelId, vDatabaseQuery);
end;

Forwarding Reverso (Forward Remoto)

// Ask the server to forward a remote port to us
oSSH.RequestForwarding('0.0.0.0', 8080);
// Cancel the forwarding
oSSH.CancelForwarding('0.0.0.0', 8080);

Keep-Alive & Opções de Conexão

Evite que conexões ociosas sejam derrubadas por firewalls ou load balancers com o mecanismo de keep-alive integrado.

// Send keep-alive every 30 seconds, disconnect after 3 failures
oSSH.KeepAlive.Enabled := True;
oSSH.KeepAlive.Interval := 30;
oSSH.KeepAlive.MaxCount := 3;
// Connection options
oSSH.SSHOptions.ConnectTimeout := 10000;  // 10 seconds
oSSH.SSHOptions.ReadTimeout := 30000;     // 30 seconds
oSSH.SSHOptions.MaxChannels := 10;       // Concurrent channels

Configuração de Algoritmos Criptográficos

Os padrões são seguros e modernos. Personalize a negociação de algoritmos quando políticas de conformidade ou compatibilidade com servidores legados exigirem.

Categoria Algoritmos Suportados
Troca de Chaves Curve25519, ECDH (P-256, P-384, P-521), DH Group14/16
Host Keys Ed25519, ECDSA (P-256, P-384, P-521), RSA (SHA2-256, SHA2-512)
Cifras AES-256/192/128-CTR, AES-256/128-GCM
MACs HMAC-SHA2-256, HMAC-SHA2-512, HMAC-SHA1
// Customize algorithm preferences
oSSH.Algorithms.KexAlgorithms := 'curve25519-sha256';
oSSH.Algorithms.Ciphers := 'aes256-gcm@openssh.com'
		,aes256-ctr';
oSSH.Algorithms.HostKeyAlgorithms := 'ssh-ed25519,rsa-sha2-256';
oSSH.Algorithms.MACs := 'hmac-sha2-256';
// Force re-keying to refresh encryption
oSSH.Rekey;

Referência de Eventos

O componente fornece callbacks de evento granulares para cada etapa do ciclo de vida SSH.

Evento Disparado quando
OnSSHConnectConexão SSH estabelecida
OnSSHDisconnectConexão SSH encerrada (com motivo e código)
OnSSHErrorErro SSH ocorre
OnSSHAuthSuccess / OnSSHAuthFailureAutenticação bem-sucedida ou falha
OnSSHHostKeyHost key precisa de verificação (aceitar/rejeitar)
OnSSHChannelDataDados (stdout) recebidos em um canal
OnSSHChannelExtendedDataDados estendidos (stderr) recebidos em um canal
OnSSHChannelExitStatusCódigo de saída do comando remoto recebido
OnSSHChannelExitSignalProcesso remoto encerrado por sinal (com nome do sinal)
OnSSHKeyboardInteractiveServidor solicita respostas keyboard-interactive
OnSSHAuthBannerServidor envia uma mensagem de banner de autenticação

Exemplo Completo: Script de Implantação Automatizada

Um cliente SSH totalmente configurado que conecta com autenticação por chave, executa comandos de implantação e captura o status de saída.

uses
  IdSSHClient, IdSSHClasses;
var
  oSSH: TIdSSHClient;
  vOutput: string;
begin
  oSSH := TIdSSHClient.Create(nil);
  Try
    // Connection
    oSSH.Host := 'production.example.com';
    oSSH.Port := 22;
    // Key-based authentication
    oSSH.Authentication.Username := 'deploy';
    oSSH.Authentication.PrivateKeyFile := 'C:\keys\deploy_ed25519';
    // Keep connection alive through firewalls
    oSSH.KeepAlive.Enabled := True;
    oSSH.KeepAlive.Interval := 30;
    // Events
    oSSH.OnSSHHostKey := OnHostKey;
    oSSH.OnSSHError := OnError;
    // Connect
    oSSH.Connect;
    // Run deployment commands
    vOutput := oSSH.Execute('cd /opt/app && git pull origin main');
    WriteLn(vOutput);
    vOutput := oSSH.Execute('systemctl restart myapp');
    WriteLn(vOutput);
    vOutput := oSSH.Execute('systemctl status myapp');
    WriteLn(vOutput);
    // Disconnect
    oSSH.Disconnect;
  Finally
    oSSH.Free;
  End;
end;