8 min de leitura

Os limites de credenciais de subdomínios de API são realmente aplicados?

Os limites de credenciais de subdomínios de API impedem que tokens cheguem a hosts vizinhos, regionais, alternativos e de tenants por meio de redirecionamentos ou código de cliente permissivo.

Os limites de credenciais de subdomínios de API são realmente aplicados?

Um nome de host não é uma indicação de propriedade. Ele faz parte da identidade do destino que determina para onde uma credencial de API vai. Se um cliente mantém um único token bearer e trata api.example.com, files.example.com, api.eu.example.com e customer.example.com como equivalentes porque compartilham um sufixo, o cliente já tomou a decisão perigosa.

Esse erro se esconde atrás de uma arquitetura amigável. Uma empresa pode ser proprietária de todos os nomes sob um domínio pai. O DNS pode enviar vários nomes para o mesmo balanceador de carga. Os certificados podem cobrir todos eles. Nada disso significa que uma credencial emitida para uma API deve chegar a outro nome de host. As credenciais precisam de uma regra de destino explícita, e essa regra precisa de testes que falhem quando alguém a ampliar mais tarde.

Nomes de host não herdam confiança de um domínio pai

api.example.com e admin.example.com podem compartilhar um domínio registrável, mas são origens separadas. Uma origem inclui esquema, host e porta. https://api.example.com e https://api.example.com:8443 também são origens separadas. A distinção importa porque o cliente escolhe um destino de rede por essa autoridade, não pela relação comercial entre os serviços.

A RFC 9110 define um espaço de proteção de autenticação HTTP usando a origem e, quando presente, um realm. Ela também alerta que depender apenas de realms pode expor credenciais a outros recursos de uma origem e recomenda hosts ou portas separados quando partes diferentes precisam de isolamento. É um alerta útil, mas não uma autorização para tratar todos os nomes sob um mesmo sufixo como um único espaço de proteção.

Engenheiros costumam misturar três ideias diferentes:

  • Um domínio pai nomeia um namespace DNS.
  • Um site agrupa origens web relacionadas para algumas regras de segurança do navegador.
  • Uma origem identifica um esquema, host e porta de um destino HTTP.

Apenas as duas primeiras fazem os subdomínios parecerem relacionados. O seu distribuidor de credenciais de API deve usar a terceira.

Isso importa mesmo quando o emissor da credencial coloca uma declaração aud ampla no token. Uma declaração de público ampla informa ao serviço receptor o que ele pode aceitar. Ela não instrui o cliente a oferecer o token a todos os endpoints que possam aceitá-lo. O remetente ainda tem o dever de minimizar a distribuição.

Já vi isso falhar de uma forma previsível. Uma equipe começa com um único endpoint, adiciona api.staging.example.com e mantém um auxiliar chamado getApiKey(). Seis meses depois, o auxiliar está sob cinco serviços. Ele não tem argumento de host, lista de permissões nem ideia do motivo pelo qual deveria recusar uma chamada. A chave não se tornou insegura porque alguém usou uma exploração exótica. Ela se tornou insegura porque o código deixou de carregar o fato de que a chave pertencia a um único destino.

Torne a vinculação ao host visível na configuração e nas revisões de código. Um seletor de credenciais que aceita apenas o nome da credencial já está sem metade da entrada necessária.

Os quatro formatos de host falham de maneiras diferentes

Hosts vizinhos, alternativos, regionais e específicos de clientes merecem casos de teste separados porque falham por motivos diferentes. Uma única asserção vaga de que o token permanece «nos nossos domínios» não detectará pelo menos um deles.

Um host vizinho fica ao lado do host pretendido: metrics.example.com em vez de api.example.com. Isso costuma expor uma entrada compartilhada, um serviço antigo ou uma ferramenta interna que nunca deveria receber credenciais de produção. Um host vizinho é especialmente perigoso quando um proxy genérico encaminha cabeçalhos sem alterações para um upstream escolhido pela configuração de rota.

Um host alternativo é um alias amigável, como api.brand.example ou developer.example.com. Os provedores criam esses nomes durante mudanças de marca, aquisições ou migrações. O alias pode terminar em uma borda diferente, usar telemetria diferente ou redirecionar para um host canônico. Não conceda acesso a credenciais com base em um redirecionamento que você viu uma vez no navegador.

Um host regional muda a localização e muitas vezes também muda a propriedade do serviço: api.us.example.com, api.eu.example.com ou api.ap-southeast.example.com. A solicitação pode transportar dados comerciais antes que a aplicação rejeite o token. Uma resposta 401 não prova que enviar a credencial e o corpo para aquela região era aceitável.

Um host específico de cliente torna os erros de multi-tenancy ainda mais graves: acme.vendor.example e northwind.vendor.example podem ser resolvidos pela mesma infraestrutura, mas cada nome representa um limite de tenant. Um token amplo o suficiente para funcionar nos dois pode ser intencional para um plano de controle central. Ele nunca deve se tornar a credencial padrão para solicitações direcionadas a tenants.

Inclua cada categoria no seu inventário. Não as reduza a um campo chamado allowed_domains presumindo que um curinga torna a política mais simples. O curinga apenas tira a decisão difícil do campo de visão.

Vincule a seleção da credencial à autoridade completa

Um cliente seguro mapeia a autoridade de uma solicitação para um único registro de credencial e recusa a solicitação quando nenhum registro corresponde. A autoridade completa significa esquema, nome de host normalizado e porta efetiva. Para uma API HTTPS comum na porta 443, a configuração visível pode continuar simples, mas a implementação ainda precisa recusar uma porta inesperada em vez de reutilizar o token silenciosamente.

Um inventário funcional pode ser assim:

credentials:
  billing-production:
    allowed:
      - https://api.billing.example.com:443
    header: Authorization
    scheme: Bearer

  telemetry-eu:
    allowed:
      - https://ingest.eu.example.net:443
    header: X-Write-Key

O ponto não é o YAML. O ponto é que o nome do token não existe sozinho. billing-production tem um destino explícito, e telemetry-eu não pode vazar para um endpoint dos Estados Unidos porque alguém alterou apenas uma string de host.

Evite este padrão:

const headers = {
  Authorization: `Bearer ${process.env.PRODUCTION_API_TOKEN}`
};

await fetch(userSuppliedUrl, { headers });

O código acoplou um destino sem restrições a uma credencial de alto privilégio. Às vezes, desenvolvedores defendem isso dizendo que a URL vem de um arquivo de configuração confiável. Esse arquivo ainda é um limite de entrada. Ferramentas de implantação, substituições de ambiente, pull requests, flags de recurso e um job de build comprometido podem alterá-lo.

Use um construtor de solicitações que se recuse a criar solicitações autenticadas até corresponder a um destino normalizado. Mantenha a normalização do host simples e rigorosa:

  1. Analise a URL com um analisador de URL real, não com verificações de sufixo de strings.
  2. Exija https:, a menos que exista uma exceção documentada para desenvolvimento local.
  3. Converta o host para minúsculas e faça a canonicalização por meio do analisador.
  4. Compare o esquema, o host e a porta resultantes com autoridades aprovadas exatas.
  5. Adicione o cabeçalho de autenticação somente depois que a correspondência for bem-sucedida.

Não escreva host.endsWith("example.com"). Isso aceita notexample.com. Também não corrija isso com endsWith(".example.com") e considere o trabalho encerrado. Essa expressão ainda concede o token a todos os subdomínios atuais e futuros, inclusive nomes delegados a um cliente, fornecedor ou ambiente de desenvolvimento esquecido.

A distinção entre autorização do destino e autorização da credencial precisa continuar clara. Uma API receptora pode rejeitar um token fora do escopo. O remetente deve impedir que o token saia para essa API desde o início. O primeiro controle limita a exposição. O segundo decide o acesso. Você precisa dos dois.

Um redirecionamento é um novo destino, não a continuação da solicitação antiga

O tratamento de redirecionamentos cria um segundo limite de credenciais. O primeiro host pode ser aprovado e depois retornar um cabeçalho Location apontando para um nome alternativo, endpoint regional, armazenamento de objetos ou host que um invasor controla por meio de um redirecionamento aberto. Se o cliente seguir automaticamente, ele deverá executar novamente a autorização do destino antes de enviar qualquer credencial ou corpo da solicitação.

O libcurl deixa essa diferença especialmente clara. Por padrão, ele não envia autenticação gerada internamente nem cabeçalhos de cookies definidos explicitamente para um host diferente durante redirecionamentos. A opção CURLOPT_UNRESTRICTED_AUTH altera esse comportamento e pode enviar credenciais para hosts escolhidos pelas respostas de redirecionamento. O projeto curl alerta que cabeçalhos personalizados exigem cuidado separado, pois a biblioteca não consegue inferir quais cabeçalhos arbitrários carregam segredos.

Esse último detalhe surpreende equipes experientes. Elas testam a autenticação Basic com um cliente padrão e veem um redirecionamento entre hosts se comportar com segurança. Depois, a integração de produção usa X-Api-Key, Authorization: Bearer ou X-Signature inserido como um cabeçalho genérico. Uma biblioteca pode preservar esse cabeçalho, a menos que a aplicação o remova. Um teste aprovado para um mecanismo de autenticação não diz nada sobre outro.

Trate os redirecionamentos por classe de solicitação:

  • Para operações de escrita, rejeite redirecionamentos, a menos que o contrato da API exija seu uso.
  • Para operações de leitura, inspecione cada destino de redirecionamento e reconstrua os cabeçalhos a partir do registro de credencial aprovado para o destino.
  • Para solicitações assinadas, recrie a assinatura depois de autorizar o destino final. Nunca encaminhe uma assinatura criada para o primeiro host.
  • Para uploads, não encaminhe o cabeçalho de autorização original para uma URL de armazenamento pré-assinada. A assinatura na query ou os campos do formulário já carregam a autoridade limitada esperada por esse endpoint de armazenamento.

Um teste de redirecionamento precisa inspecionar a solicitação que chega ao segundo servidor. Verificar apenas o código de status final não basta. Uma resposta 200 de um receptor de teste inofensivo pode esconder o fato de que ele recebeu o cabeçalho de produção que você pretendia proteger.

As tentativas novamente precisam da mesma disciplina. Alguns wrappers HTTP reconstroem solicitações a partir de um mapa de cabeçalhos armazenado em cache. Se uma nova tentativa seguir a descoberta de serviço até uma nova autoridade, descarte o mapa em cache e consulte novamente o seletor de credenciais. Reutilizar cabeçalhos é mais rápido. Também é assim que o contexto do destino desaparece.

Crie um ambiente de testes negativos antes de confiar na lista de permissões

Revogue uma execução problemática do agente
Revogue uma sessão de agente em execução no diário de Sessões quando o processo deixar de merecer autorização.

O teste que importa é negativo: uma credencial deve aparecer no host pretendido e não deve aparecer em todos os hosts plausíveis errados. Você pode executar isso com dois servidores HTTPS locais, mas o receptor deve registrar apenas a presença e o nome dos cabeçalhos sensíveis. Não coloque valores reais nos logs de teste.

Para uma verificação no nível do shell, mapeie nomes inofensivos para servidores locais com a opção --resolve do curl e use um token descartável. Inicie um receptor na porta 8443 para o host aprovado e outro na porta 9443 para o vizinho. Cada receptor deve produzir um registro com este formato:

host=api.test.example
path=/v1/ping
authorization=present
x-api-key=absent

O receptor vizinho deve produzir o resultado inverso:

host=metrics.test.example
path=/v1/ping
authorization=absent
x-api-key=absent

Depois, exercite o wrapper de cliente HTTP real, não uma versão isolada da lógica. Uma sondagem com curl pode expor a configuração básica:

curl --silent --show-error \\
  --resolve api.test.example:8443:127.0.0.1 \\
  --header 'Authorization: Bearer test-token-do-not-use' \\
  https://api.test.example:8443/v1/ping

Esse comando coloca intencionalmente o cabeçalho na solicitação, portanto só prova o que o receptor registra. Ele não prova que a aplicação seleciona as credenciais com segurança. O teste da aplicação deve chamar a função normal request() com a mesma autoridade aprovada, repetir com cada autoridade errada e verificar que um erro é gerado antes de qualquer conexão ser aberta.

Use uma matriz que force as decisões que as pessoas normalmente deixam de lado:

Autoridade solicitadaComportamento esperado da credencial
https://api.test.exampleEnviar a credencial de teste pretendida
https://metrics.test.exampleRecusar antes de enviar
https://api.eu.test.exampleRecusar, a menos que esteja configurado separadamente
https://tenant-a.test.exampleRecusar, a menos que a vinculação ao tenant seja explícita
Host aprovado redirecionando para um vizinhoSeguir somente após nova autorização, normalmente sem a credencial original

Não use um serviço externo de request-bin para esse teste. Você ensinaria sua equipe a enviar segredos de teste para terceiros enquanto verifica se envia segredos a terceiros. Um receptor local é simples e mantém as evidências sob seu controle.

Coloque a matriz na integração contínua. Um teste unitário de isAllowedHost() ajuda, mas um teste de integração captura a regressão comum: alguém adiciona um cabeçalho padrão a uma camada HTTP inferior depois que a verificação do host já foi executada.

As regras do navegador não são regras do agente

O vocabulário dos navegadores causa suposições equivocadas em código de agentes e backends. «Same site» pode incluir subdomínios, enquanto «same origin» não inclui. A MDN usa https://example.org e https://login.example.org como exemplo de duas origens que pertencem ao mesmo site. Essa distinção existe porque um subdomínio comprometido pode atacar um vizinho por meio de caminhos same-site.

O Fetch usa credentials: "same-origin" por padrão, o que impede que o fetch do navegador inclua credenciais automaticamente em solicitações entre origens. Um desenvolvedor pode ver esse padrão, testar uma chamada do frontend e concluir que um token bearer não pode passar de um subdomínio para outro. Essa conclusão não se sustenta no código do servidor. Um wrapper fetch de backend pode anexar qualquer cabeçalho que seu autor fornecer. Uma CLI pode fazer o mesmo. Um agente autônomo pode chamar uma ferramenta HTTP genérica com uma URL e cabeçalhos, a menos que a ferramenta mantenha a credencial fora do alcance do agente.

O CORS não corrige isso. O CORS controla principalmente se o JavaScript do navegador pode ler uma resposta. Ele não transforma um injetor amplo de cabeçalhos do lado do servidor em um distribuidor seguro de credenciais. Em algumas solicitações do navegador, o navegador pode enviar a credencial e depois se recusar a expor a resposta ao script. Isso não é um controle aceitável de prevenção contra perda de dados.

Os cookies acrescentam outra fonte de confusão. Os atributos de domínio dos cookies podem permitir que um cookie chegue aos subdomínios, enquanto cookies host-only não permitem. Cabeçalhos bearer não têm um escopo de domínio integrado comparável. Se o seu cliente anexa Authorization, ele tomou uma decisão explícita para aquela solicitação. Não use modelos mentais de cookies para chaves de API.

Domínios de clientes precisam de um limite de emissor, não de uma convenção de nomes

Aprove o uso de chaves sensíveis
Marque uma chave para aprovação por chamada e confirme cada uso com um clique ou Touch ID.

Uma API central pode chamar legitimamente muitos endpoints de clientes, mas precisa de credenciais que expressem por que a chamada pode atravessar limites de tenants. A configuração mais segura fornece a cada host de cliente um registro de credencial separado e com escopo restrito. A segunda melhor configuração usa um token de curta duração cujas declarações de público e tenant são verificadas pelo destino, com uma lista de clientes que ainda nomeia cada host permitido.

Um token global com uma função ampla é popular porque facilita a integração. Adicione um tenant, aponte a integração para o subdomínio dele e a chamada funciona. A mesma conveniência permite que um erro de digitação, uma alteração maliciosa de configuração ou um agente confuso alcance o serviço de outro cliente com uma credencial sem um limite de destino significativo.

Não resolva isso criando *.customers.example.com como um padrão aprovado e dizendo a si mesmo que cada correspondência é um cliente. Pergunte quem pode criar esses nomes, quem pode delegar o DNS, quais hosts direcionam para ambientes de preview e se os nomes persistem depois que um cliente deixa de usar o serviço. Um curinga transforma todas essas perguntas em decisões de segurança, geralmente sem deixar um registro de revisão.

Há casos em que um curinga controlado é apropriado. Um provedor pode emitir tokens por tenant em que o token inclui um identificador de tenant, o serviço rejeita incompatibilidades e um registro interno verifica o host do tenant antes que o cliente envie a solicitação. Nesse desenho, o curinga não é a regra de autorização. É apenas uma conveniência restrita atrás de um registro de tenants que tem autoridade. Se você não consegue nomear esse registro e testar seu comportamento em caso de falha, use entradas exatas.

O DNS privado cria o mesmo problema dentro de uma empresa. payments.prod.internal e payments.dev.internal podem não ser nomes públicos, mas são destinos diferentes com controles operacionais diferentes. O DNS interno não substitui o escopo das credenciais.

As verificações de host devem ocorrer antes da descoberta e depois da normalização

Verifique o registro de auditoria offline
Verifique o log de auditoria encadeado por hash do Sallyport offline, sobre texto cifrado, com sp audit verify e sem uma chave.

A descoberta de serviços, o roteamento personalizado e a configuração de proxy podem contornar silenciosamente uma lista de permissões que parecia adequada. Se o código verifica a URL original e depois um resolvedor substitui o destino interno, a aplicação pode enviar uma credencial para outra autoridade. Por outro lado, uma verificação que usa um cabeçalho Host mutável pode aprovar uma solicitação cuja conexão de rede vai para outro lugar.

Use a autoridade da URL analisada como entrada da política. Estabeleça a conexão TLS para essa autoridade e verifique o certificado normalmente. Não desative a verificação de certificados para fazer uma rota interna ou um dispositivo de teste funcionar. As próprias orientações de segurança do curl dizem que um cliente que não consegue autenticar o par não pode saber se chegou ao servidor pretendido.

Depois, decida o que o seu modelo de confiança diz sobre proxies. Um proxy de encaminhamento é uma escolha de transporte, não um novo destino de credencial, se o cliente estabelecer TLS com a origem aprovada por meio dele. Um proxy reverso que termina o TLS faz parte do limite do serviço e precisa do mesmo nível de análise que a própria API. Um proxy HTTP que recebe cabeçalhos de autorização em texto simples tem acesso às credenciais. Não chame esse detalhe de «apenas infraestrutura».

Normalize nomes de host internacionalizados por meio de uma implementação de URL compatível com os padrões e compare o resultado canônico. Rejeite informações de usuário em URLs como https://[email protected]/; credenciais em URLs vazam para logs, históricos e saídas de depuração. Rejeite fragmentos em solicitações HTTP e decida explicitamente se strings de consulta podem conter credenciais pré-assinadas. Uma função genérica de sanitização não consegue salvar um desenho que aceita qualquer URL e espera identificar as ruins depois.

A ordem importante é simples: analisar, normalizar, autorizar o destino, selecionar a credencial, construir os cabeçalhos, conectar. Se qualquer operação posterior alterar a autoridade, recomece pela autorização do destino.

Audite a decisão, não o segredo

Um registro de auditoria deve provar qual destino o cliente considerou e qual regra de credencial selecionou, sem registrar o segredo. Você precisará desse registro quando alguém perguntar se um token poderia ter chegado a um host vizinho depois de uma alteração na implantação.

Armazene campos como ID da solicitação, horário, autoridade normalizada, ID do registro de credencial, resultado da autorização, origem e destino do redirecionamento e um código de resultado. Faça hash ou oculte os caminhos quando eles contiverem identificadores de clientes. Não registre Authorization, cabeçalhos de chaves personalizados, strings de consulta com assinaturas ou corpos completos de solicitações apenas porque eles ajudam na depuração.

Uma boa entrada de auditoria responde a uma pergunta concreta:

request_id=01J...
authority=https://api.billing.example.com:443
credential=billing-production
destination_check=allowed
redirect_count=0
result=201

Para uma solicitação rejeitada a um host vizinho, o registro deve mostrar credential=none e destination_check=denied. Essa distinção prova que o cliente recusou a solicitação antes de selecionar um segredo. Se o log mostrar um nome de credencial e depois informar um 403 do host errado, o sistema já enviou mais do que deveria.

O Sallyport mantém o segredo no cofre criptografado e avalia uma ação antes que o agente receba qualquer material de credencial. Os diários de Atividade e Sessões oferecem às equipes uma forma de inspecionar o caminho da ação e revogar uma sessão de agente em execução quando uma solicitação vinculada a um host dá errado.

Comece pelo inventário. Para cada credencial, escreva uma autoridade pretendida e depois nomeie um host vizinho, um nome alternativo ou de migração, um nome regional e um nome específico de cliente que não devem recebê-la. Se o seu cliente não consegue fazer essas asserções negativas hoje, ele não tem um limite de credenciais. Tem apenas uma convenção esperançosa.

FAQ

As chaves de API funcionam automaticamente em subdomínios?

Não. api.example.com e billing.example.com são origens diferentes, mesmo quando a mesma equipe administra os dois nomes. Trate a vinculação de uma credencial como exata, a menos que o emissor documente explicitamente um público mais amplo e você tenha testado esse escopo.

É seguro enviar um único token bearer para todos os subdomínios?

Eles só devem receber o token se o seu cliente estiver configurado deliberadamente para enviá-lo a esses locais. Um domínio pai comprova a propriedade de um namespace, não a autorização para reutilizar a credencial bearer de um serviço.

Um redirecionamento HTTP pode vazar uma credencial de API para outro host?

Um redirecionamento pode mudar o destino depois da primeira solicitação, portanto o tratamento de redirecionamentos precisa de sua própria verificação de host. Nunca presuma que um cliente HTTP remove um cabeçalho de credencial personalizado apenas porque remove a autenticação HTTP integrada.

Cada subdomínio de cliente deve usar uma credencial separada?

Não. Um host como tenant-a.api.example.com normalmente deve ter uma credencial vinculada ao tenant ou um token com uma declaração de tenant que o serviço aplique. Uma chave administrativa geral apontada para hosts de tenants transforma um erro de roteamento em um incidente entre tenants.

Os endpoints de API regionais precisam de credenciais separadas?

Sim, se o endpoint regional tiver um nome de host diferente. O fato de dois serviços regionais pertencerem ao mesmo provedor não torna os nomes intercambiáveis, e erros de região podem enviar dados para o limite de residência errado antes mesmo que a autenticação falhe.

Domínios alternativos de API são seguros para credenciais de produção?

Nomes alternativos são arriscados porque parecem inofensivos e muitas vezes ficam diante de estruturas diferentes de roteamento, registro ou propriedade. Vincule as credenciais ao host canônico do serviço, a menos que o provedor documente o nome alternativo como um público autenticado equivalente.

Como testo se meu cliente envia um token para domínios vizinhos?

Registre a URL exata, a credencial selecionada, o comportamento do redirecionamento e se a solicitação levou um cabeçalho de autenticação. O teste mais útil executa um endpoint inofensivo contra hosts aprovados e deliberadamente não aprovados, falhando se a credencial aparecer em qualquer lugar onde não deveria.

O CORS impede que credenciais cheguem a um subdomínio?

O CORS controla o que o JavaScript do navegador pode ler, enquanto os cookies têm suas próprias regras de domínio e SameSite. Um agente no servidor, uma CLI ou um cliente HTTP personalizado pode enviar qualquer cabeçalho para qualquer host, a menos que o código impeça essa solicitação.

Devo usar listas de hosts curinga para credenciais de API?

Para tokens bearer, cabeçalhos de chave de API personalizados e destinos SSH, listas de hosts exatos geralmente são a opção certa. Use um curinga restrito somente quando o próprio sistema de credenciais comprovar o tenant ou o público do serviço selecionado e você puder verificar continuamente quais hosts concretos corresponderam.

Qual é a primeira correção para um erro no limite de credenciais?

A primeira correção é inventariar todas as vinculações entre credenciais e hosts e eliminar padrões amplos, como *.example.com. Depois, adicione um teste negativo para cada credencial: um destino aprovado deve recebê-la, enquanto destinos vizinhos, alternativos, regionais e de tenants não devem.

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