1
0
Files
spring-security-demo/ssrf/docs/05-wiring-it-up.md
2026-08-29 09:31:09 +05:30

3.8 KiB

← Where the filter runs · Module README · Operating it →

5. Wiring it up, and the three ways it silently does nothing

The bean

@Configuration(proxyBeanMethods = false)
public class OutboundConfiguration {

    @Bean
    InetAddressFilter httpClientInetAddressFilter() {
        return InetAddressFilter.externalAddresses();
    }

}

HttpClientAutoConfiguration.httpClientSettings reads it and folds it into the shared HttpClientSettings:

InetAddressFilter filter = inetAddressFilter.getIfAvailable();
HttpClientSettings settings = (filter != null)
        ? HttpClientSettings.defaults().withInetAddressFilter(filter)
        : HttpClientSettings.defaults();

Note that HttpClientSettings.defaults() is the all-null record — the default filter is null, not all().

There is no property for it

HttpClientSettingsProperties carries redirects, connectTimeout, readTimeout, cookieHandling and ssl. There is no spring.http.clients.inet-address-filter. Configuration is a bean or an explicit HttpClientSettings, and nothing else — so it cannot be turned on per environment from a config server, and it cannot be turned off in an incident without a deploy.

Plan for that: put the filter behind a @Profile or a @ConditionalOnProperty yourself if you need a switch.

Failure 1 — the starter does not bring it

spring-boot-starter-web alone does not put InetAddressFilter on the classpath, and does not give you an auto-configured RestClient.Builder either. Boot 4 split the HTTP client modules apart. The compile error is the good outcome:

cannot find symbol
  symbol:   class FilteredHostException

Add spring-boot-starter-restclient (or -webclient), which pulls in spring-boot-restclient and through it spring-boot-http-client. This module's pom.xml does exactly that.

Failure 2 — a client you built yourself

The filter reaches auto-configured builders. A RestClient.create() or a new RestTemplate() written inside your own class is not one, and no bean will change it. That is why LinkPreviewController takes RestClient.Builder in its constructor.

For a hand-built client, apply the filter yourself:

HttpClientSettings settings = HttpClientSettings.defaults()
        .withInetAddressFilter(InetAddressFilter.externalAddresses());
ClientHttpRequestFactory factory = ClientHttpRequestFactoryBuilder.jdk().build(settings);

And note what is still not covered: anything that opens a socket without going through a Spring HTTP client. A JDBC URL, a raw URL.openStream(), an SDK with its own transport, a ProcessBuilder running curl. InetAddressFilter is a control on Spring's HTTP clients, not an egress policy for the JVM. If you need the latter, it belongs in the network.

Failure 3 — two beans, and a diagnostic that blames the wrong thing

getIfAvailable() is not "pick one". Two InetAddressFilter beans and the context does not start — see docs/output/two-filter-beans.txt:

No qualifying bean of type 'org.springframework.boot.http.client.InetAddressFilter' available:
expected single matching bean but found 2: firstFilter,secondFilter

but the framed message Boot prints underneath names something four levels away:

Description:
Parameter 0 of method restClientBuilder in ...RestClientAutoConfiguration required a single
bean, but 2 were found:

The words InetAddressFilter do not appear in the part everyone reads. If you are merging two starters or two shared config modules, this failure will look like a RestClient problem.

Operating it →