Campo "servidor" na tela de login: trocar a connection string é poder de administrador
Tire a troca de banco da mão do usuário final: ambiente define a conexão, administrador escolhe de uma lista, o builder monta a string e tudo fica auditado.
O ERP desktop da distribuidora tem, na tela de login, um botão "Configurar servidor" com um campo de texto livre. Numa segunda-feira, uma pessoa do financeiro digita o servidor de homologação que viu num e-mail antigo e passa a manhã lançando pagamentos numa base de teste. Na semana seguinte, um prestador digita o IP de uma máquina dele, e o ERP, obediente, envia usuário e senha do SQL Server para lá.
A resposta curta: para onde o sistema se conecta é decisão de infraestrutura, não preferência de usuário. O ambiente (variável de ambiente, arquivo de configuração do servidor ou da instalação) define a conexão. Se um administrador precisa trocar, a troca é uma ação explícita, autenticada, escolhida de uma lista de servidores permitidos, montada com o builder do driver, testada antes de gravar e registrada em log. Nunca concatene texto do formulário numa connection string.
Por que um campo de servidor é perigoso
Uma connection string carrega quatro coisas sensíveis: para onde ir, em que banco entrar, com que credencial e com que segurança de transporte. Deixar o usuário final mexer nisso abre três problemas diferentes:
- Base errada. Lançamentos em homologação somem; testes em produção viram dado real. Os dois erros são caros e difíceis de desfazer.
- Credencial entregue a terceiros. Na autenticação SQL, o cliente envia usuário e senha ao servidor. Apontar o aplicativo para uma máquina controlada por outra pessoa entrega a credencial para ela.
- Alcance da rede interna. Num sistema web, o servidor da aplicação faz a conexão. Um campo de servidor vira uma forma de fazer a sua aplicação testar portas e máquinas internas que o usuário não alcançaria.
Há ainda a injeção na própria string. Connection strings são pares chave=valor separados por ponto e vírgula, e, quando uma chave aparece mais de uma vez, vale a última. Se o código faz "Server=sql-prod;Database=" + banco e alguém digita vendas;Server=10.0.0.9 no campo de banco, o servidor muda sem que ninguém tenha tocado no campo de servidor.
Como tratar a conexão do jeito certo
- Tire o campo da tela de login. Usuário final escolhe, no máximo, a empresa ou filial, nunca o servidor.
- Defina a conexão por ambiente. Em aplicações web, por variável de ambiente ou cofre de segredos. Em aplicações desktop, num arquivo de configuração da instalação, protegido por permissão de administrador.
- Se a troca for necessária, crie uma tela de administração. Só para perfil administrativo, com nova autenticação, e com lista fechada de ambientes.
- Monte a string com o builder do driver. Ele escapa valores e impede que um campo vire outro.
- Teste antes de gravar. Abra a conexão com timeout curto e rode uma consulta simples. Falhou, não grava.
- Registre a mudança. Quem trocou, quando, de qual ambiente para qual, de que máquina. Sem a senha.
- Nunca mostre a senha de volta. A tela exibe o ambiente e o usuário, e a senha só pode ser substituída.
Exemplo: seletor de ambiente em C# com SqlConnectionStringBuilder
O código usa Microsoft.Data.SqlClient. Desde a versão 4 dessa biblioteca, a conexão é criptografada por padrão; não desligue a validação do certificado do servidor para "fazer funcionar".
using Microsoft.Data.SqlClient;
using Microsoft.Extensions.Logging;
public sealed class SeletorDeAmbiente
{
private static readonly IReadOnlyDictionary<string, string> Servidores =
new Dictionary<string, string>
{
["Produção"] = "sql-prod.distribuidora.local",
["Homologação"] = "sql-hml.distribuidora.local"
};
private readonly ILogger<SeletorDeAmbiente> _log;
public SeletorDeAmbiente(ILogger<SeletorDeAmbiente> log) => _log = log;
public static IEnumerable<string> Ambientes => Servidores.Keys;
public static string Montar(string ambiente, string banco)
{
if (!Servidores.TryGetValue(ambiente, out var servidor))
throw new ArgumentException("Ambiente não permitido: " + ambiente);
var b = new SqlConnectionStringBuilder
{
DataSource = servidor,
InitialCatalog = banco,
IntegratedSecurity = true, // conta do Windows, sem senha guardada
ConnectTimeout = 5
};
return b.ConnectionString;
}
public async Task<string> TrocarAsync(string administrador, string ambienteAtual, string novoAmbiente, string banco)
{
string cs = Montar(novoAmbiente, banco);
await using (var conn = new SqlConnection(cs))
{
await conn.OpenAsync();
await using var cmd = new SqlCommand("SELECT 1", conn);
await cmd.ExecuteScalarAsync();
}
_log.LogWarning(
"Conexão alterada por {Administrador}: de {De} para {Para}, banco {Banco}",
administrador, ambienteAtual, novoAmbiente, banco);
return cs; // quem chama grava na configuração protegida da instalação
}
}
Repare no que o código não aceita: texto livre para servidor. A lista de ambientes é fixa e revisada em código. O nome do banco, que ainda vem de fora, passa pelo builder, que o trata como valor de InitialCatalog, e não como pedaço da string. Com IntegratedSecurity, a autenticação usa a conta do Windows e não há senha de banco para guardar ou exibir.
E nas aplicações web
Em ASP.NET Core, a string fica fora do código e da tela. A aplicação lê com builder.Configuration.GetConnectionString("Principal"), e o valor vem do arquivo de configuração do ambiente ou de uma variável ConnectionStrings__Principal definida no servidor ou no container. Trocar de banco é um deploy ou uma mudança de configuração revisada, não um formulário. O mesmo vale para segredos no container, como em segredo não entra na imagem do container.
Se a senha do banco já esteve num arquivo versionado ou numa tela, o primeiro passo é trocá-la, como explicado em segredo no Git se troca antes de limpar. E, para o conector em si, trave a versão no projeto em vez de depender da máquina.
Erros comuns
- Campo de servidor livre na tela de login. Qualquer pessoa aponta o sistema para a base errada ou para uma máquina que coleta a credencial.
- Concatenar valores do formulário na string. Um ponto e vírgula no campo de banco troca o servidor ou a credencial.
- Gravar sem testar. A configuração quebrada derruba todos os usuários no próximo login.
- Exibir a senha atual na tela de configuração. Quem passa atrás da cadeira leva a credencial do banco.
- Desligar a validação do certificado para o erro sumir. A conexão passa a aceitar qualquer servidor que se apresente, inclusive um falso.
- Trocar sem log. Quando os lançamentos aparecem na base errada, ninguém sabe quem mudou nem quando.
Checklist
- A tela de login não tem campo de servidor nem de connection string.
- A conexão vem de configuração do ambiente ou da instalação, protegida contra usuário comum.
- A troca de ambiente, se existir, exige perfil administrativo e escolhe de uma lista fechada.
- A string é montada com o builder do driver, nunca por concatenação.
- A conexão é testada antes de a configuração ser gravada.
- Cada troca gera um registro com autor, data, origem e destino, sem senha.
- A validação do certificado do servidor continua ligada.
Entre no seu sistema com um usuário comum, sem privilégio nenhum: existe algum caminho, tela ou arquivo editável que faça a aplicação falar com outro servidor?