8 min de leitura

Precedência de cabeçalhos HTTP: acabe com os conflitos de identidade da API

A precedência dos cabeçalhos HTTP pode dividir a identidade de uma API entre clientes e proxies. Aprenda a rejeitar com segurança cabeçalhos Authorization e personalizados duplicados.

Precedência de cabeçalhos HTTP: acabe com os conflitos de identidade da API

Uma requisição com duas credenciais não é uma requisição com autenticação de reserva. É uma instrução ambígua entregue a uma cadeia de softwares que pode interpretá-la de forma diferente em cada salto. Já vi equipes passarem horas culpando uma API depois que um proxy escolheu silenciosamente um valor de Authorization e a aplicação escolheu outro. O sintoma parece aleatório até alguém imprimir os cabeçalhos brutos em cada limite.

A precedência dos cabeçalhos HTTP precisa de uma regra que você consiga dizer em uma frase, testar na rede e aplicar antes da autenticação: uma requisição que forneça mais de um valor para um único campo de credencial sensível à segurança deve falhar. Não escolha o primeiro. Não escolha o último. Não una os valores com uma vírgula. Essas escolhas transformam um comportamento incidental da implementação em sua política de autenticação.

Isso importa além de Authorization. Muitas APIs aceitam X-API-Key, um cabeçalho personalizado de tenant, um timestamp de requisição assinada ou um campo de identidade encaminhado. Quando as credenciais passam por clientes, balanceadores de carga, tradutores de protocolo e middleware da aplicação, o tratamento de duplicidades passa a fazer parte do limite de segurança.

O HTTP não define um vencedor geral

O HTTP define a sintaxe dos campos e fornece regras especiais de combinação para alguns campos repetidos, mas não diz que o primeiro campo Authorization vence em todo lugar ou que o último vence em todo lugar. O destinatário precisa interpretar a seção de campos recebida de acordo com a semântica do campo e com sua própria implementação.

A RFC 9110 diz que um destinatário pode combinar várias linhas de campo com o mesmo nome em um único valor separado por vírgulas quando a definição do campo permitir uma lista separada por vírgulas. Ela também diz que o destinatário não deve combinar linhas quando a definição do campo não permitir isso. Essa distinção costuma ser ignorada. «Os cabeçalhos podem ser agrupados» não é uma regra para todos os cabeçalhos. É uma regra para campos projetados como listas.

Accept é um contraste útil. Um cliente pode enviar várias linhas Accept, e um destinatário geralmente pode tratar seus valores como uma única lista de tipos de mídia aceitos. Authorization carrega credenciais para uma requisição. Não é uma lista genérica de credenciais intercambiáveis. Uma vírgula também pode ter significado dentro da sintaxe de um esquema de autenticação. Unir dois valores pode criar uma string que nenhum cliente pretendia enviar e que diferentes parsers interpretam de formas diferentes.

Os nomes dos campos de cabeçalho não diferenciam maiúsculas de minúsculas. Estes são duplicados:

Authorization: Bearer token-a
authorization: Bearer token-b

Um detector que compare a grafia original não perceberá isso. Normalize o nome antes de contar os valores.

Não confunda linhas de campo duplicadas com vários desafios de autenticação em WWW-Authenticate. Um servidor pode anunciar vários esquemas aceitos em uma resposta. Nesse caso, o servidor está oferecendo opções. Uma requisição com dois valores Authorization é o cliente apresentando credenciais conflitantes. São problemas diferentes e precisam de tratamentos diferentes.

O mesmo alerta vale quando uma API aceita um campo de credencial padrão e um personalizado. Uma API pode aceitar deliberadamente Authorization: Bearer ... ou X-API-Key: .... A menos que a documentação defina como resolver os dois juntos, enviar ambos cria um conflito de identidade. Rejeite a requisição. Um fallback que existe apenas em algum middleware não é um contrato.

Os clientes tornam os cabeçalhos duplicados mais fáceis do que parecem

A possibilidade de um cliente emitir cabeçalhos repetidos depende do modelo de requisição da biblioteca. Bibliotecas que expõem os cabeçalhos como um mapa geralmente sobrescrevem um valor quando o código atribui o mesmo nome duas vezes. Bibliotecas que expõem um array ou uma coleção de vários valores podem enviar ambos. Nenhum desses comportamentos prova o que o próximo salto receberá.

Com o curl, repita -H para solicitar dois campos:

curl --http1.1 -v https://api.example.test/orders \
  -H 'Authorization: Bearer first' \
  -H 'Authorization: Bearer second'

O rastreamento detalhado deve mostrar duas linhas de saída semelhantes a estas:

> Authorization: Bearer first
> Authorization: Bearer second

Isso prova apenas a requisição HTTP/1.1 de saída do curl nessa conexão. Não prova que a borda, o balanceador de carga ou a aplicação receberam os dois valores. Teste um endpoint controlado por você antes de usar esse padrão contra uma API de produção. Os tokens dos exemplos devem ser descartáveis, e tokens Bearer reais nunca devem aparecer em uma gravação de terminal ou em um chamado de suporte.

Em JavaScript, o objeto Headers comum tem semânticas que surpreendem muita gente. set() substitui o valor atual. append() adiciona outro valor conceitualmente, mas a serialização e a semântica do cabeçalho continuam importantes. Um desenvolvedor pode achar que enviou dois cabeçalhos quando a biblioteca, na verdade, construiu um valor unido por vírgula. É exatamente por isso que os testes de autenticação precisam inspecionar a entrada bruta, em vez de apenas examinar um objeto em memória.

O código de servidor do Node.js tem sua própria armadilha. req.headers geralmente expõe nomes normalizados e pode apresentar uma visão agrupada. req.rawHeaders preserva uma lista alternada de nomes e valores recebidos em requisições HTTP/1.1. Um diagnóstico seguro deve contar os nomes normalizados a partir da representação bruta e evitar imprimir valores secretos:

function duplicateNames(rawHeaders) {
  const counts = new Map();
  for (let i = 0; i < rawHeaders.length; i += 2) {
    const name = rawHeaders[i].toLowerCase();
    counts.set(name, (counts.get(name) || 0) + 1);
  }
  return [...counts.entries()].filter(([, count]) => count > 1);
}

console.log(duplicateNames(req.rawHeaders));
// Example output: [ [ 'authorization', 2 ] ]

Use isso como auxílio de diagnóstico, não como autorização para interpretar manualmente todos os cabeçalhos da aplicação. Seu framework ou gateway deve fazer a rejeição efetiva no primeiro ponto confiável. A ideia é revelar o que o objeto conveniente de cabeçalhos escondeu.

Cabeçalhos personalizados merecem a mesma desconfiança. Um cliente pode adicionar X-API-Key duas vezes por acidente, por meio de uma camada de cabeçalhos padrão e outra específica da requisição. Também pode enviar um valor Authorization herdado de um wrapper corporativo do cliente enquanto o código adiciona explicitamente uma chave de API. A API pode parecer funcionar nos testes locais porque o caminho local não usa o wrapper. Em produção, os dois conjuntos de credenciais chegam juntos e o comportamento muda.

Os proxies podem mudar a requisição e as evidências

Um proxy reverso é um destinatário HTTP e um novo remetente HTTP. Ele não apenas transporta bytes do cliente para a aplicação. Ele interpreta a requisição recebida, aplica configurações, pode traduzir protocolos e escreve uma nova requisição para o upstream. Isso lhe dá muitas oportunidades de preservar duplicidades, descartá-las, agrupá-las ou criar um novo cabeçalho de credencial.

O caso perigoso é a interpretação dividida. Imagine que um cliente envie:

Authorization: Bearer attacker-token
Authorization: Bearer service-token

Um componente de borda mantém o primeiro valor para sua verificação de acesso. A biblioteca do upstream apresenta o último valor à aplicação. A borda autoriza uma identidade e a aplicação executa o trabalho como outra. Mesmo que nenhum dos componentes tenha um erro de parsing, a cadeia não atribui um significado único à requisição.

Uma falha mais comum é menos dramática. Uma configuração de proxy adiciona um campo Authorization de upstream para uma credencial de serviço, mas esquece de remover o campo recebido. O serviço de destino escolhe um valor conforme um comportamento que ninguém documentou. Uma atualização posterior do proxy, uma migração de rota ou a troca de HTTP/1.1 por HTTP/2 muda qual valor sobrevive. A equipe chama isso de indisponibilidade intermitente de autenticação porque nunca registrou a duplicidade.

Os campos encaminhados criam um problema de identidade relacionado. X-Forwarded-User, X-Forwarded-Client-Cert e cabeçalhos de identidade personalizados costumam viajar de uma borda confiável até uma aplicação. A borda pública precisa remover as cópias fornecidas pelo cliente antes de adicionar as próprias. Se encaminhar cópias não confiáveis, uma aplicação que confie na posição errada da lista pode aceitar uma identidade forjada.

A regra muda um pouco conforme o limite de confiança:

  • Na entrada pública, rejeite campos de autenticação duplicados e remova cabeçalhos de identidade internos fornecidos pelo cliente.
  • Em um gateway confiável, injete a única credencial ou o único cabeçalho de identidade exigido pelo upstream depois de remover a entrada protegida do cliente.
  • Na aplicação, rejeite as duplicidades novamente. A defesa na entrada é necessária, mas mudanças de rota acabam contornando suposições.
  • Nos logs, registre o nome do cabeçalho, a quantidade, a rota e o identificador da requisição. Registre o esquema da credencial apenas se isso for seguro.

Não dependa do comportamento padrão de um proxy sem testá-lo. Os padrões variam conforme o produto, o módulo, o protocolo e a configuração. Uma opção que trata cabeçalhos de resposta duplicados não informa nada sobre credenciais de requisição duplicadas. Leia a documentação da diretiva ou do middleware exato e depois envie uma requisição realmente duplicada pelo caminho implantado.

HTTP/2 e HTTP/3 removem a sintaxe antiga, não a ambiguidade

HTTP/2 e HTTP/3 não enviam linhas textuais de cabeçalho pela rede, mas continuam transportando uma sequência de campos de cabeçalho. As regras do protocolo proíbem campos pseudo-cabeçalho duplicados, como :method, e exigem que eles apareçam antes dos campos comuns. Essas regras ajudam na correção do protocolo. Elas não dão à Authorization uma regra universal de precedência.

Um endpoint HTTP/2 pode receber campos de cabeçalho comuns repetidos. Uma biblioteca pode expô-los como valores separados, como um valor combinado ou como um erro, dependendo do campo e da API. HTTP/3 traz a mesma preocupação prática no nível da aplicação. Você precisa testar as versões de protocolo aceitas pela sua borda.

A tradução de protocolos é onde as suposições se deterioram. Um cliente fala HTTP/2 com uma CDN ou um balanceador de carga. A CDN fala HTTP/1.1 com um gateway. O gateway fala HTTP/2 com um serviço. Cada salto precisa traduzir uma representação de cabeçalho. Se o primeiro salto agrupa um campo e o segundo o preserva, a aplicação final não consegue reconstruir a requisição original. Esse é outro motivo para o primeiro destinatário confiável rejeitar a ambiguidade, em vez de tentar uma recuperação engenhosa mais tarde.

O HTTP/2 também trata os cabeçalhos específicos da conexão de forma diferente. Campos como Connection são proibidos porque descrevem o comportamento de conexão do HTTP/1.1. Isso não tem relação com a precedência de credenciais. Não copie uma regra de cabeçalho específica do protocolo presumindo que ela protege um cabeçalho de autenticação personalizado.

Algumas equipes tentam resolver isso usando nomes em minúsculas porque o HTTP/2 exige nomes de campos em minúsculas na rede. Isso corrige apenas um problema trivial. Os nomes do HTTP/1.1 também não diferenciam maiúsculas de minúsculas, e um gateway pode receber HTTP/1.1 antes de receber HTTP/2. Normalize os nomes em todos os lugares.

Monte sua matriz de testes em torno dos caminhos, não apenas dos protocolos. Exercite uma requisição direta à aplicação em um ambiente de teste, a rota pública e qualquer rota interna usada por workers ou ferramentas de implantação. Para cada rota, envie Authorization duplicado, cabeçalhos de credencial personalizados duplicados e dois canais de credencial conflitantes. O resultado esperado deve ser o mesmo erro explícito para o cliente em todos os casos.

Escolher o primeiro ou o último cria uma superfície de ataque

Verifique a trilha de ações offline
O registro de auditoria criptografado e encadeado por hashes pode ser verificado offline com sp audit verify, sem uma chave.

«Use o primeiro cabeçalho» parece conservador porque lembra um parser lendo da esquerda para a direita. «Use o último» parece prático porque uma configuração posterior deveria substituir padrões anteriores. As duas regras falham porque o remetente e cada intermediário podem influenciar a ordem de maneiras diferentes.

A escolha do primeiro é vulnerável quando um atacante consegue inserir uma credencial antes de um componente confiável adicionar a sua. A escolha do último é vulnerável quando o atacante consegue acrescentar uma credencial depois que um componente confiável verificou a primeira. O exploit exato depende do roteamento e da confiança, mas o erro de projeto é estável: um componente seleciona uma credencial enquanto outro enxerga uma requisição diferente.

Agrupar por vírgulas é pior do que qualquer uma das duas opções quando produz uma string aparentemente válida. Considere um cabeçalho personalizado de chave de API em que a aplicação divide pelo caractere de vírgula, mas o gateway compara a string inteira. Ou considere um parser Bearer que aceita o texto depois do primeiro espaço e não rejeita vírgulas. Você acabou de criar duas linguagens de parsing para um campo que contém um segredo.

A recomendação popular de «deixar a API decidir» está errada quando um gateway faz qualquer autenticação, limitação de taxa, roteamento por tenant ou classificação de auditoria antes de a requisição chegar à API. O gateway já tomou uma decisão de segurança. Ele precisa usar a mesma identidade inequívoca que o serviço ou interromper a requisição.

Um contrato previsível se parece com isto:

  1. Normalize o nome de todos os cabeçalhos recebidos.
  2. Conte todas as ocorrências dos campos protegidos antes de selecionar as credenciais.
  3. Rejeite duplicidades de cada campo protegido com um erro genérico do cliente.
  4. Rejeite canais de credencial incompatíveis quando a rota aceitar apenas uma fonte de identidade.
  5. Remova os campos protegidos recebidos antes de um componente confiável injetar suas próprias credenciais de upstream.

Faça isso antes do parsing do token. Se o parsing do token ocorrer primeiro, um parser pode consumir um valor que o componente seguinte teria rejeitado. Mantenha a resposta de erro simples. Informe ao cliente que a requisição contém cabeçalhos de autenticação conflitantes, sem repetir os valores dos campos.

Existem APIs raras que definem deliberadamente vários valores para um campo. Se você mantém uma API assim, documente a gramática, a ordem, o comportamento das duplicidades e os requisitos do proxy como parte do contrato de autenticação. «O framework resolve isso» não é documentação. Se você não mantém a API, não invente um esquema de precedência para ela.

Cabeçalhos personalizados precisam de um contrato de credencial

As equipes costumam tratar Authorization como sensível e os cabeçalhos personalizados como simples infraestrutura. Isso está invertido. Um cabeçalho personalizado que seleciona uma chave de API ou um tenant é material de autenticação, independentemente de seu nome começar com X-.

Registre quais canais de credencial cada rota aceita. Uma rota pode aceitar um token Bearer vindo de Authorization. Outra pode aceitar uma assinatura de webhook em um cabeçalho específico junto com um timestamp. Uma rota interna pode receber um cabeçalho de identidade somente de um gateway. São contratos separados. Evite um middleware genérico que aceite a primeira credencial que encontrar.

Um contrato de credencial precisa responder a estas perguntas:

  • Esse campo pode aparecer mais de uma vez?
  • Ele pode aparecer junto com outro campo de credencial?
  • Qual componente confiável pode adicioná-lo?
  • Um proxy o remove antes de encaminhá-lo?
  • Qual erro a API retorna quando encontra um conflito?

Para chaves de API, use um de dois modelos claros. O primeiro aceita exatamente um esquema Authorization. O segundo aceita exatamente um cabeçalho de chave de API nomeado. Não ofereça os dois na mesma rota, a menos que exista uma necessidade de migração e uma regra de conflito documentada. Durante uma migração, rejeite requisições que contenham ambos e mostre aos clientes uma mensagem sem data de validade que identifique a alternativa aceita. Manter um fallback silencioso para sempre cria um problema permanente de diagnóstico.

Webhooks assinados exigem cuidado adicional. Os cabeçalhos de assinatura podem conter legitimamente parâmetros estruturados, e um timestamp pode acompanhar a assinatura. Isso não significa que campos de assinatura duplicados sejam seguros. Consulte a documentação de verificação do provedor e preserve o tratamento esperado do corpo bruto. Se ela não definir assinaturas repetidas, rejeite-as antes da verificação. Nunca as concatene esperando que a biblioteca de verificação escolha a opção pretendida.

Os cabeçalhos de identidade internos são os mais fáceis de usar errado porque são convenientes. Se uma aplicação aceita X-User-Id da rede pública e presume que um proxy o inseriu, o cliente pode declarar qualquer identidade. Vincule os cabeçalhos internos a um caminho de rede privado ou a uma conexão autenticada com o proxy, remova-os em todas as bordas públicas e valide que somente seu proxy confiável consegue alcançar a porta da aplicação. A precedência de cabeçalhos não corrige um limite de confiança de rede mal configurado.

Teste a rota inteira com conflitos deliberados

Mantenha as chaves SSH fora dos agentes
O Sallyport também executa comandos SSH pelo auxiliar integrado, mantendo as chaves SSH fora do agente.

Testes unitários de um parser de token não testam a precedência de cabeçalhos. Você precisa de um teste de integração que atravesse os mesmos componentes usados em produção. O resultado desejado é simples e estável: toda requisição ambígua deve ser rejeitada antes que uma ação upstream aconteça.

Comece com um endpoint inofensivo sob seu controle. Dê a ele um identificador de requisição e faça com que retorne apenas observações seguras: nomes de cabeçalho normalizados, quantidades, versão do protocolo e o componente que recebeu a requisição. Não retorne valores dos cabeçalhos. Depois, coloque-o atrás da mesma borda, do mesmo gateway e do mesmo roteamento de serviço usados pela API-alvo.

Execute um pequeno conjunto de conflitos:

Authorization duas vezes, com o mesmo valor
Authorization duas vezes, com valores diferentes
Authorization junto com X-API-Key
X-API-Key duas vezes, com o mesmo valor
Um cabeçalho de identidade interno fornecido pelo cliente junto com a identidade do gateway

O caso com o mesmo valor é importante. Alguns desenvolvedores rejeitam apenas valores diferentes porque consideram os iguais inofensivos. Isso cria uma distinção de parsing que um atacante pode testar e deixa invisível um erro acidental de duplicação. Rejeite qualquer campo protegido duplicado. Um cliente que tente novamente com um único campo ainda poderá se autenticar.

Verifique dois resultados para cada caso. Primeiro, o cliente recebe uma resposta 4xx explícita do limite que é responsável pela regra. Segundo, o sistema upstream não registra nenhuma ação sob nenhuma das duas identidades. Um 401 ou 403 isolado não prova que a rota é segura; um sistema upstream pode ter processado parte da requisição antes de rejeitá-la.

Depois, repita o teste para cada protocolo e caminho aceito. Inclua as bibliotecas de cliente usadas pela automação, não apenas o curl. Um cliente de linha de comando, um wrapper de fetch do navegador, uma biblioteca HTTP de CI e um runtime de agente podem montar coleções de cabeçalhos de maneiras diferentes. Mantenha o teste na suíte de implantação para que uma atualização do proxy ou do framework não substitua silenciosamente uma rejeição por uma regra de seleção.

Quando ocorrer um incidente, capture evidências seguras na ordem correta. Registre a construção da requisição no cliente, a decisão de acesso da borda, os cabeçalhos de saída do gateway como nomes e quantidades e a observação de entrada da aplicação. Relacione tudo com um único identificador de requisição. Não resolva um incidente de cabeçalho duplicado ativando o registro completo de cabeçalhos em produção. É assim que um erro de autenticação vira uma exposição de credenciais.

Os gateways devem controlar a injeção de credenciais de saída

Pare de entregar chaves de API aos agentes
Credenciais Bearer, Basic e de cabeçalhos personalizados permanecem criptografadas no cofre do Sallyport, fora do contexto do agente.

Um gateway de ações deve manter o agente longe das credenciais brutas e tornar um único componente responsável pela requisição final de saída. Passar um token Bearer ao agente e pedir que ele monte os cabeçalhos dá a ele autoridade e muitas formas de criar uma requisição malformada. Também dificulta a interpretação dos registros de auditoria quando cabeçalhos padrão e personalizados entram em conflito.

O Sallyport executa chamadas HTTP com credenciais injetadas a partir de seu cofre criptografado, em vez de expor o segredo ao agente. Esse limite só é útil se o construtor da requisição de saída tratar os cabeçalhos de credencial como campos protegidos, não como sugestões que os cabeçalhos fornecidos pelo agente possam substituir.

Para um cabeçalho de saída protegido, o gateway deve selecionar a configuração de credencial salva, remover qualquer instância fornecida pelo cliente desse campo sem diferenciar maiúsculas de minúsculas e adicionar exatamente um valor final. Deve aplicar a mesma regra aos cabeçalhos de credencial personalizados. Se a requisição de destino precisar de um cabeçalho controlado pelo agente com o mesmo nome, a configuração está errada ou a API de destino precisa de uma rota separada. Não crie uma exceção por requisição que altere a identidade silenciosamente.

Existe uma distinção importante. Remover um cabeçalho Authorization fornecido pelo agente antes de adicionar o configurado é adequado no limite confiável de saída. Aceitar dois cabeçalhos esperando que o destino resolva o problema não é. A primeira ação estabelece uma única fonte de credencial. A segunda exporta a ambiguidade.

Um gateway também precisa proteger contra canais concorrentes. Suponha que uma conexão salva injete Authorization: Bearer ..., enquanto a requisição do agente inclua X-API-Key. O destino pode aceitar qualquer um dos dois. O padrão mais seguro é rejeitar a requisição como contendo credenciais conflitantes, a menos que a definição da conexão permita explicitamente essa combinação e documente o motivo. Uma lista genérica de cabeçalhos permitidos não consegue responder a isso, porque o significado pertence à API de destino.

Os registros de auditoria devem informar ao operador que o gateway usou uma conexão ou um rótulo de credencial nomeado, qual host recebeu a requisição, o método, o caminho e se houve aprovação humana. Eles não devem armazenar o valor de Authorization nem o cabeçalho personalizado secreto. O diário de Atividade do Sallyport foi projetado em torno de chamadas individuais, mas um diário não corrige uma requisição ambígua depois do fato. O construtor da requisição precisa remover a ambiguidade antes que ela saia da máquina.

Os logs revelam falhas de precedência sem vazar tokens

Bugs de cabeçalhos duplicados sobrevivem porque as equipes registram pouco demais para enxergar a mudança de rota ou registram demais e criam um segundo incidente. É possível registrar o suficiente para diagnosticar o problema sem guardar credenciais.

Para cada conflito rejeitado, registre uma lista normalizada dos nomes dos cabeçalhos protegidos e suas quantidades. Acrescente o nome da rota, o protocolo, o componente que recebeu a requisição, o identificador da requisição e um código de motivo, como duplicate_authorization ou conflicting_credential_channels. Se o processo operacional permitir, registre um identificador da configuração de credencial que não possa ser usado para recuperar o segredo.

Nunca registre tokens Bearer brutos, chaves de API, valores de autenticação básica, payloads de webhook assinados, cookies ou linhas Authorization completas. A redação depois da formatação da string não é confiável. Uma biblioteca pode lançar uma exceção que inclua a requisição original, ou um logger de depuração pode ser executado antes do seu redator. Construa os registros a partir de campos seguros, em vez de capturar um dump da requisição e tentar limpá-lo depois.

Fazer hash de um token não é automaticamente seguro. Um hash estável pode permitir que qualquer pessoa com acesso aos logs relacione o uso da mesma credencial e pode ser vulnerável a tentativas quando o segredo tem baixa entropia. Use um ID de credencial não secreto vindo do cofre ou da configuração se precisar fazer correlações. Se não tiver um, registre que havia um canal de credencial não identificado e corrija o modelo de configuração.

Trate a falta de evidências como uma falha de implantação. Se uma borda rejeitar uma duplicidade, mas a trilha de auditoria não mostrar qual borda tomou a decisão, os responsáveis perderão tempo comparando logs da aplicação que nunca recebeu a requisição. Por outro lado, se a aplicação a rejeitar, mas a borda permitir sua passagem, você encontrou um ponto onde pode reforçar a aplicação da regra.

A primeira correção prática é pequena: enumere os cabeçalhos que carregam credenciais em uma rota pública, rejeite repetições e conflitos na entrada e prove com um teste de integração que nenhuma chamada upstream ocorre. Depois aplique o mesmo contrato a todos os caminhos de proxy e clientes de saída. A ordem dos cabeçalhos nunca deve decidir quem uma API pensa que está chamando.

FAQ

Qual cabeçalho HTTP vence quando o mesmo cabeçalho aparece duas vezes?

O HTTP não define um vencedor universal para nomes de campos duplicados. Um destinatário pode combinar alguns campos, rejeitar a requisição, manter o primeiro valor, manter o último ou encaminhar ambos. Campos sensíveis à segurança precisam de uma regra explícita em cada limite.

Uma API deve aceitar dois cabeçalhos Authorization?

Trate cabeçalhos Authorization duplicados como uma falha da requisição. Escolher o primeiro ou o último faz com que a credencial aceita dependa do comportamento do cliente e das alterações feitas pelo proxy, o que cria um contrato de segurança ruim. Rejeite a requisição antes da autenticação e registre a duplicidade com segurança.

O HTTP/2 pode criar cabeçalhos duplicados?

Eles podem aparecer, e isso é uma fonte séria de confusão. HTTP/2 e HTTP/3 transportam campos de cabeçalho em blocos estruturados, enquanto um trecho HTTP/1.1 pode serializá-los de outra forma. O gateway precisa manter a regra de rejeição de duplicidades durante a tradução entre protocolos.

Os proxies reversos agrupam cabeçalhos HTTP duplicados?

Um proxy reverso pode manter os dois campos, agrupá-los, remover um deles ou adicionar suas próprias credenciais. A configuração e a ordem dos módulos determinam o resultado, não o navegador ou o cliente da API. Teste a rota implantada exatamente como ela existe, em vez de presumir que o proxy é transparente.

Posso enviar Authorization e X-API-Key juntos?

Use um cabeçalho separado somente quando o serviço o documentar explicitamente, como X-API-Key ou um cabeçalho de credencial específico do fornecedor. Não o envie junto com Authorization como alternativa. O servidor deve rejeitar requisições que apresentem credenciais conflitantes, a menos que a documentação defina uma escolha segura e determinística.

Authorization e authorization são cabeçalhos diferentes?

Não. Os nomes dos cabeçalhos HTTP não diferenciam maiúsculas de minúsculas, portanto authorization, Authorization e AUTHORIZATION indicam o mesmo campo. Um detector de duplicidades deve comparar nomes normalizados, não a forma original como foram escritos.

Posso combinar cabeçalhos Authorization duplicados com uma vírgula?

Não agrupe cabeçalhos Authorization com uma vírgula. Vírgulas podem aparecer na sintaxe de autenticação, e um cabeçalho de autenticação geralmente não é um campo de lista. Rejeite a requisição ou remova o campo indesejado em um limite confiável, seguindo uma regra documentada.

Como depuro cabeçalhos de requisição duplicados com segurança?

Inspecione a requisição bruta em cada salto: cliente, proxy de borda, gateway da aplicação e aplicação. Registre nomes de cabeçalhos e metadados seguros, como tamanhos ou esquema da credencial, mas nunca tokens Bearer. Um listener local ajuda a provar o que o cliente realmente enviou.

O primeiro cabeçalho Authorization é sempre usado?

Evite depender da ordem da requisição. Bibliotecas diferentes preservam, reordenam, agrupam ou substituem campos repetidos, e os intermediários podem alterar sua representação na rede. Uma API segura se comporta da mesma forma ao rejeitar todas as duplicidades, independentemente da ordem.

Cabeçalhos de autenticação personalizados também podem ser duplicados?

Não presuma que ele permanecerá igual. Alguns clientes conseguem enviar cabeçalhos personalizados repetidos, enquanto outros substituem uma entrada de mapa, e os intermediários podem aplicar sua própria normalização. Capture a requisição na rede em um teste isolado e mantenha esse teste nas verificações de lançamento.

Sallyport

O Sallyport executa chamadas de API e comandos SSH pelo seu agente de IA. As chaves ficam em um cofre local no seu Mac; você aprova cada execução e toda ação vai para um registro selado.

© 2026 Sallyport · Código aberto sob Apache-2.0 · Oleg Sotnikov