Solucionado (ver solução)
Solucionado
(ver solução)
4
respostas

[Dúvida] Como tratar com APIs escondidas para a construção da URI

Olá, tudo bem?
Existe algumas ferramentas, que por fins de segurança, adicionam camadas para acessar uma API no servidor real. Afim de evitar ataques DDOS. E acredito que não seja conveniente que o servidor repasse essa URI do servidor real, na resposta, mesmo que ela seja bloqueada a nível de rede, seria uma URI inválida, que não acessa o recurso de maneira esperada.
Então, sobre isso faço uma pergunta: tem como fazer alguma configuração para alterar o domínio base da URI? Ou ainda, isso já é feito de alguma forma inteligente por estas ferramentas?

4 respostas

Olá Pedro, tudo bem?

Quando utilizamos ferramentas que adicionam camadas de segurança, como proxies reversos ou firewalls de aplicação, é comum que a URI do servidor real não seja exposta diretamente para o cliente. Isso é feito para proteger o servidor de ataques, como o DDoS, que você mencionou.

Para resolver a questão de alterar o domínio base da URI, o Spring Boot, junto com o UriComponentsBuilder, pode ajudar bastante. Você pode configurar o UriComponentsBuilder para construir URIs que apontem para o domínio desejado, sem expor o domínio real do servidor.

Aqui está um exemplo de como você pode fazer isso:

@PostMapping
@Transactional
public ResponseEntity cadastrar(@RequestBody @Valid DadosCadastroMedico dados, UriComponentsBuilder uriBuilder) {
    var medico = new Medico(dados);
    repository.save(medico);

    // Aqui você pode definir o host que deseja expor
    UriComponents uriComponents = uriBuilder
        .scheme("https")
        .host("api.exemplo.com")
        .path("/medicos/{id}")
        .buildAndExpand(medico.getId());

    return ResponseEntity.created(uriComponents.toUri()).body(new DadosDetalhamentoMedico(medico));
}

No exemplo acima, o UriComponentsBuilder é utilizado para construir a URI com o domínio que você deseja expor (api.exemplo.com). Assim, mesmo que o servidor real esteja em um domínio diferente, a URI retornada para o cliente será a que você configurou.

Espero ter ajudado e bons estudos!

Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓.

Entendi
Obrigado
Porém supondo que eu tenha um service que service como base em diferentes hosts. A única alternativa seria colocar como parâmetro e alterar este, ou teria uma forma mais inteligente para resolver?

solução!

Oi, Pedro!

Sobre sua última dúvida, não é necessário passar o host como parâmetro manualmente em cada caso quando sua aplicação está atrás de proxy reverso, gateway ou load balancer.

O caminho mais inteligente é fazer o Spring usar os headers de encaminhamento enviados por essa camada, como X-Forwarded-Host, X-Forwarded-Proto, X-Forwarded-Port e Forwarded. Assim, o UriComponentsBuilder monta a URI com base no domínio externo que o cliente realmente acessou, e não no endereço interno do servidor.

Resolva fazendo o seguinte:

  1. Configure o Spring Boot para respeitar os headers do proxy no application.properties:

    
     server.forward-headers-strategy=framework
     
  2. Garanta que o proxy ou gateway envie os headers corretos. Os mais usados são:

  • X-Forwarded-Host
  • X-Forwarded-Proto
  • X-Forwarded-Port
  • X-Forwarded-Prefix (se houver prefixo na rota, como /api)
  1. Continue construindo a URI normalmente no controller e ajuste seu código assim:

    @PostMapping
    @Transactional
    public ResponseEntity<DadosDetalhamentoMedico> cadastrar(
            @RequestBody @Valid DadosCadastroMedico dados,
            UriComponentsBuilder uriBuilder) {
    
        var medico = new Medico(dados);
        repository.save(medico);
    
        var uri = uriBuilder
                .path("/medicos/{id}")
                .buildAndExpand(medico.getId())
                .toUri();
    
        return ResponseEntity
                .created(uri)
                .body(new DadosDetalhamentoMedico(medico));
    }
    

    Com isso, se a requisição chegar externamente por: https://api.seudominio.com a URI gerada no Location será montada com esse domínio externo, desde que o proxy esteja repassando os headers corretamente.

Pontos importantes:

  • Se sua aplicação atende vários hosts, essa abordagem funciona melhor porque o host é resolvido dinamicamente por requisição.
  • Você só precisará fixar domínio manualmente quando a infraestrutura não enviar os headers de encaminhamento.
  • Em cenários com API Gateway, Nginx, Traefik, Apache ou Cloudflare, isso normalmente já faz parte da configuração da camada de entrada, mas precisa estar habilitado corretamente.

Se quiser validar se está funcionando, teste exibindo os dados recebidos na requisição:


@GetMapping("/teste-host")
public String teste(HttpServletRequest request) {
    return "scheme=" + request.getScheme()
            + ", host=" + request.getServerName()
            + ", port=" + request.getServerPort();
}

Se o retorno mostrar o domínio público em vez do host interno, a configuração está certa.

Fico à disposição!

Entendi,
Mutissimo obrigado...