Skip to content

Commit

Permalink
Make X-Real-IP take precedence over Remote-Address
Browse files Browse the repository at this point in the history
Update documentation and migration notes accordingly.
  • Loading branch information
raboof committed May 20, 2020
1 parent 964a3cb commit 81c28df
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,21 @@ class MiscDirectivesSpec extends RoutingSpec {
extractClientIP { echoComplete }
} ~> check { responseAs[String] shouldEqual "2.3.4.5" }
}
"extract from a Remote-Address header" in {
Get() ~> addHeaders(`X-Real-Ip`(remoteAddress("1.2.3.4")), `Remote-Address`(remoteAddress("5.6.7.8"))) ~> {
"extract from a (synthetic) Remote-Address header" in {
Get() ~> addHeader(`Remote-Address`(remoteAddress("1.2.3.4"))) ~> {
extractClientIP { echoComplete }
} ~> check { responseAs[String] shouldEqual "5.6.7.8" }
} ~> check { responseAs[String] shouldEqual "1.2.3.4" }
}
"extract from a X-Real-IP header" in {
Get() ~> addHeader(`X-Real-Ip`(remoteAddress("1.2.3.4"))) ~> {
extractClientIP { echoComplete }
} ~> check { responseAs[String] shouldEqual "1.2.3.4" }
}
"select X-Real-Ip when both X-Real-Ip and Remote-Address headers are present" in {
Get() ~> addHeaders(`X-Real-Ip`(remoteAddress("1.2.3.4")), `Remote-Address`(remoteAddress("5.6.7.8"))) ~> {
extractClientIP { echoComplete }
} ~> check { responseAs[String] shouldEqual "1.2.3.4" }
}
"extract unknown when no headers" in {
Get() ~> {
extractClientIP { echoComplete }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ object MiscDirectives extends MiscDirectives {

private val _extractClientIP: Directive1[RemoteAddress] =
headerValuePF { case `X-Forwarded-For`(Seq(address, _*)) => address } |
headerValuePF { case `Remote-Address`(address) => address } |
headerValuePF { case `X-Real-Ip`(address) => address } |
headerValuePF { case `Remote-Address`(address) => address } |
extractRequest.map { request =>
request.attribute(AttributeKeys.remoteAddress).getOrElse(RemoteAddress.Unknown)
}
Expand Down
10 changes: 10 additions & 0 deletions docs/src/main/paradox/migration-guide/migration-guide-10.2.x.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,13 @@ Prior to 10.2.0, when a client would perform a `HEAD` request, by default Akka H
This can save bandwidth in some cases, but is also counter-intuitive when you actually want to explicitly handle `HEAD` requests,
and may increase resource usage in cases where the logic behind the `GET` request is heavy. For this reason we have changed
the default value of `akka.http.server.transparent-head-requests` to `off`, making this feature opt-in.

### X-Real-Ip now takes precedence over Remote-Address in extractClientIP

The @ref[extractClientIP](../routing-dsl/directives/misc-directives/extractClientIP.md) now returns the value of the
`X-Real-Ip` header when both an`X-Real-Ip` and a `Remote-Address` header is available. This directive provides a
'best guess' of the client IP, but in a way that allows any client to provide this address in the header. For this reason
you should never trust this value for security purposes.

When you need a secure way to get the client IP, use the @apidoc[AttributeKeys.remoteAddress](AttributeKeys) @ref[attribute](../common/http-model.md#attributes),
or use the specific headers which are known to be set correctly by the infrastructure you do trust.
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,16 @@

## Description

Provides the value of `X-Forwarded-For`, `Remote-Address`, `X-Real-IP` headers or `AttributeKeys.remoteAddress` attribute as an instance of `RemoteAddress` in that order. If the value in the header first seen is an invalid IP address and the attribute is absent, this extractor will return `RemoteAddress.Unknown`.
Provides the value of the `X-Forwarded-For` or `X-Real-IP` header.
If neither of those is found it will fall back to the value of the synthetic `RemoteAddress` header (`akka.http.server.remote-address-header` setting is `on`)
or the value of the @apidoc[AttributeKeys.remoteAddress](AttributeKeys) @ref[attribute](../../../common/http-model.md#attributes) (if the `akka.http.server.remote-address-attribute` setting is `on`)

The akka-http server engine adds the `Remote-Address` header to every request automatically if the respective
setting `akka.http.server.remote-address-header` is set to `on`, and adds the `AttributeKeys.remoteAddress` attribute if the
setting `akka.http.server.remote-address-attribute` is set to `on`. Per default both are set to `off`.

@@@ note
The setting `akka.http.server.remote-address-header` will be deprecated because the producing `Remote-Address` header is synthetic and confused,
and will cover a real `Remote-Address` header passed by the client. If you want a direct http client IP address, please use `akka.http.server.remote-address-attribute` instead.
@@@
If no valid IP address is encountered, this extractor will return RemoteAddress.Unknown`.

@@@ warning
Clients can send any values in these headers. If the client is not a trusted upstream, the IP address can be malicious and by pass your security rules.
Clients can send any values in these headers. If the client is not a trusted upstream, the IP address can be malicious.
For sensitive operations use the @apidoc[AttributeKeys.remoteAddress](AttributeKeys) @ref[attribute](../../../common/http-model.md#attributes),
or use the specific headers which are known to be set correctly by the infrastructure you do trust.
@@@

## Example
Expand Down

0 comments on commit 81c28df

Please sign in to comment.