blog.wlami.com

Virtuelles Zuhause von Wladislaw Mitzel

X-Forwarded Header in Apache CXF auslesen

Betreibt man Web-Applikationen hinter einem Load Balancer so bekommt man in den normalen IP-Headern nur die IP-Adresse der Load Balancer. Mit den X-Fowarded http-Headern hat sich ein Quasi-Standard entwickelt, der von den meisten Load Balancern implementiert wird. Apache CXF erlaubt das automatische Auslesen dieser Header. Vorher möchte ich aber kurz auf die Bedeutung eingehen:

  • X-Forwarded-For: Dieser Header enthält die IP Adresse des Clients für den der Load Balancer den Aufruf weitergeleitet hat. Kommen auf dem Weg vom Client zum Backend mehrere Load Balancer zum Einsatz werden auch die IP Adressen der Zwischenstationen, durch Komma getrennt, in diesem Header mitgegeben.
  • X-Forwarded-Proto: Dieser Header enthält das Protokoll (http oder https) mit dem der Client den Service aufgerufen hat. Es wird beispielsweise um bei URLs das korrekte Protokoll zurückzugeben. Das Protokoll zwischen Client, Load Balancer und Backend kann sich durchaus unterscheiden wenn beispielsweise der Load Balancer auch den TLS Endpoint darstellt und die Backend Services nur noch über http aufruft.
  • Es gibt auch noch weitere X-Forwarded Header auf die ich hier aber nicht eingehe da sie weniger weit verbreitet sind und auch nicht von CXF behandelt werden.

CXF ab Version 3.0.2 bzw. 3.1.0 erlaubt uns nun mit einem relativ unbekannten Feature die genannten Header automatisch auslesen zu lassen. Mit dem Ticket CXF-5937 wurde zu diesem Zweck ein neuer Servlet Parameter implementiert: use-x-forwarded-headers. Wird dieser aktiviert, verarbeitet CXF die http-Header aus und legt sie in einem Filter, der HttpServletRequestWrapper implementiert, ab. Liest man nun die IP Adresse aus der Message aus, kommt der Filter zum Einsatz und gibt, falls vorhanden, die Original-IP Adresse zurück.

Ihr müsst also eure Servlet Definition in eurer web.xml anpassen:

(web.xml) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  version="2.5"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee           http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <display-name>cxf</display-name>
  <servlet>
      <servlet-name>cxf</servlet-name>
      <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
      <init-param>
          <description>Liest X-Forwarded Header aus</description>
          <param-name>use-x-forwarded-headers</param-name>
          <param-value>true</param-value>
      </init-param>
      <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
      <servlet-name>cxf</servlet-name>
      <url-pattern>/services/*</url-pattern>
  </servlet-mapping>
</web-app>

In den Zeilen 8 - 12 seht ihr den neuen Init Parameter use-x-forwarded-headers, der mit true belegt wird. Mehr ist nicht zu tun!

Wenn ihr nun in eurem Web Service Aufruf, wie bisher auch, die Client Adresse aus der Message holt, bekommt ihr den Wert aus dem Header:

Implementierung eines Beispiel Services (Service.java) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@WebService
public class Service {
  
  @WebMethod(action = "sayHello")
  public String sayHello(@WebParam(name = "name") String name) {
      String address = getClientAddress();
      return "Hello " + name + ". You came from " + address + "!" ;
  }

  private String getClientAddress() {
      Message message = PhaseInterceptorChain.getCurrentMessage();
      HttpServletRequest request = (HttpServletRequest)message.get(AbstractHTTPDestination.HTTP_REQUEST);
      return request.getRemoteAddr();
  }
}

Wir testen das ganze noch mit SoapUI indem wir die WSDL importieren und einen Beispiel-Aufruf erstellen. Bisher haben wir noch nichts mit den HTTP Headern gemacht, sodass 127.0.0.1 ausgegeben wird.

Und jetzt setzen wir den HTTP Header in SoapUI und schauen uns das Ergebnis an:

Der Service verwendet nun den Wert aus dem X-Forwarded-For Header! Am Beispiel sieht man auch, wieso dieses Feature nicht standardmäßig aktiviert ist: für einen nicht ganz wohlgesinnten Client ist es ein Leichtes falsche Werte in diesem Header zu übergeben. Ein Load Balancer sollte das behandeln. Ist kein Load Balancer vorgeschaltet, macht es auch keinen Sinn diese Header zu verarbeiten.

Wenn ihr selbst damit etwas rumspielen wollt, könnt ihr Euch das im Beispiel verwendete Projekt hier herunterladen: cxf-forwarded-example.zip

Kommentieren

Dieses Blog verwendet statische Kommentare. Kommentare werden also per Mail an mich geschickt und erscheinen anschließend im Blog. Eure E-Mail-Adresse wird nicht veröffentlicht.

Kommentar schreiben