Add the ssrf module
This commit is contained in:
98
ssrf/docs/05-wiring-it-up.md
Normal file
98
ssrf/docs/05-wiring-it-up.md
Normal file
@@ -0,0 +1,98 @@
|
||||
[← Where the filter runs](04-where-the-filter-runs.md) · [Module README](../README.md) · [Operating it →](06-operating-it.md)
|
||||
|
||||
# 5. Wiring it up, and the three ways it silently does nothing
|
||||
|
||||
## The bean
|
||||
|
||||
```java
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class OutboundConfiguration {
|
||||
|
||||
@Bean
|
||||
InetAddressFilter httpClientInetAddressFilter() {
|
||||
return InetAddressFilter.externalAddresses();
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
`HttpClientAutoConfiguration.httpClientSettings` reads it and folds it into the shared
|
||||
`HttpClientSettings`:
|
||||
|
||||
```java
|
||||
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`](../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`](../src/main/java/com/ankurm/ssrf/LinkPreviewController.java) takes
|
||||
`RestClient.Builder` in its constructor.
|
||||
|
||||
For a hand-built client, apply the filter yourself:
|
||||
|
||||
```java
|
||||
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`](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 →](06-operating-it.md)
|
||||
Reference in New Issue
Block a user