webentwicklung-frage-antwort-db.com.de

sichern von Websocket-Verbindungen mit Apache

Ich habe einen Apache, der nur über HTTPS erreichbar ist. Ich möchte Websockets von einer zusätzlichen Serveranwendung aus bereitstellen, die auf demselben Computer ausgeführt wird. Da es Clients jedoch nicht möglich ist, eine Verbindung mit einem anderen Port als 443 zu unserem Server herzustellen, müssen diese Websocket-Verbindungen über den Apache verbunden werden.

Nun habe ich mod_proxy installiert und wie folgt konfiguriert:

SSLProxyEngine on
ProxyPass /ws https://127.0.0.1:9001

Das funktioniert aber nicht. Ich kann jetzt eine Verbindung zu https: // server/ws in meinem Browser herstellen, aber der Apache scheint einen Teil der Websockets-Header zu verschlucken, sodass echte Websocket-Verbindungen nicht funktionieren.

Wie kann ich meine Websocket-Verbindungen über den Apache-Server tunneln?

20
mstud

Ich habe es funktioniert.

Szenario

-------------       ----------------       ----------
| Browser   |<----->| Apache httpd |<----->| Tomcat |
|           |  SSL  |    2.4.9     |  SSL  | 7.0.52 |
-------------       ----------------       ----------

Browser WebSocket über Apache httpd, Reverse-Proxying zur Web-App in Tomcat. Alle SSL von vorne nach hinten.

Hier ist die Konfiguration für jedes Stück:

Browser-Client

Beachten Sie das abschließende "/" in der URL: wss://Host/app/ws/. Die korrekte wss-ProxyPass-Anweisung (die weiter unten in der Apache-Konfigurationssektion angezeigt wird) muss angepasst werden, und eine 301-Weiterleitung zu https://Host/app/ws soll verhindert werden. Das heißt, es wurde mit dem https-Schema und nicht mit dem wss-Schema für das Back-End umgeleitet.

<!doctype html>
<body>

<script type="text/javascript">
    var connection = new WebSocket("wss://Host/app/ws/");

    connection.onopen = function () {
        console.log("connected");
    };

    connection.onclose = function () {
        console.log("onclose");
    };

    connection.onerror = function (error) {
        console.log(error);
    };
</script>

</body>
</html>

Apache httpd

Ich verwende Apache httpd 2.4.9, der standardmäßig mod_proxy_wstunnel zur Verfügung stellt. Das bereitgestellte mod_proxy_wstunnel.so unterstützt jedoch kein SSL, wenn Sie das Schema wss: // verwenden. Es wird versucht, eine Verbindung zum Back-End (Tomcat) im Klartext herzustellen, wodurch der SSL-Handshake fehlschlägt. Siehe Fehler hier . Daher müssen Sie mod_proxy_wstunnel.c selbst patchen, indem Sie die vorgeschlagene Korrektur im Fehlerbericht befolgen. Es ist ein einfacher 3-Zeilen-Wechsel. 

Suggested correction,
314a315
>     int is_ssl = 0;
320a322
>         is_ssl = 1;
344c346
<     backend->is_ssl = 0;
---
>     backend->is_ssl = is_ssl;

Dann bauen Sie das Modul neu auf und ersetzen es in Ihrem neuen mod_proxy_wstunnel.so durch das alte.

Gebäude Apache httpd

Hier ist der Befehl (2.4.9), mit dem ich die gewünschten Module eingebaut habe. Sie brauchen sie vielleicht nicht alle.

./configure --prefix=/usr/local/Apache --with-included-apr --enable-alias=shared
--enable-authz_Host=shared --enable-authz_user=shared 
--enable-deflate=shared --enable-negotiation=shared 
--enable-proxy=shared --enable-ssl=shared --enable-reqtimeout=shared
--enable-status=shared --enable-auth_basic=shared
--enable-dir=shared --enable-authn_file=shared
--enable-autoindex=shared --enable-env=shared --enable-php5=shared
--enable-authz_default=shared --enable-cgi=shared
--enable-setenvif=shared --enable-authz_groupfile=shared
--enable-mime=shared --enable-proxy_http=shared
--enable-proxy_wstunnel=shared

Beachten Sie den letzten Schalter: --enable-proxy_wstunnel=shared Zuerst verwendete ich falsch --enable-proxy-wstunnel=shared, was anscheinend gut zu bauen schien, aber letztendlich nicht funktionierte, wenn ich die resultierende .so-Datei verwendete. Sieh den Unterschied? Sie möchten sicherstellen, dass Sie einen Unterstrich in "proxy_wstunnel" anstelle eines Bindestrichs verwenden.

Apache httpd config

...
LoadModule proxy_module modules/mod_proxy.so
...
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
...
LoadModule ssl_module modules/mod_ssl.so
...
Include conf/extra/httpd-ssl.conf
...
LogLevel debug
ProxyRequests off

# Note, this is the preferred ProxyPass configuration, and *should* be equivalent
# to the same inline version below, but it does NOT WORK!
#<Location /app/ws/>
#        ProxyPass wss://localhost:8443/app/ws
#        ProxyPassReverse wss://localhost:8443/app/ws
#</Location>
#<Location /app/>
#        ProxyPass https://localhost:8443/app/
#        ProxyPassReverse https://localhost:8443/app/
#</Location>

# NOTE: Pay strict attention to the slashes "/" or lack thereof!
# WebSocket url endpoint
ProxyPass /app/ws/ wss://localhost:8443/app/ws
ProxyPassReverse /app/ws/ wss://localhost:8443/app/ws

# Everything else
ProxyPass /app/ https://localhost:8443/app/
ProxyPassReverse /app/ https://localhost:8443/app/

Wenn Sie meine Notiz in der obigen Konfig nicht gesehen haben, hier ist es wieder: Beachten Sie die Schrägstriche "/" oder deren Fehlen!

Wenn Sie in Ihrem Apache-Protokoll Debug-Protokollanweisungen sehen, die besagen, dass eine WSS-Verbindung hergestellt und dann geschlossen wurde, ist es möglich, dass Sie mod_reqtimeout wie ich aktiviert haben. Stellen Sie also sicher, dass sie nicht geladen wird:

#LoadModule reqtimeout_module modules/mod_reqtimeout.so

Kater

Angenommen, Ihr HTTP-Connector ist korrekt eingerichtet. In Tomcat muss nicht viel konfiguriert werden. Um das Debugging zu erleichtern, fand ich es hilfreich, einen $CATALINA_HOME/bin/setenv.sh zu erstellen, der so aussah:

CATALINA_OPTS=$CATALINA_OPTS" -Djavax.net.debug=all -Djavax.net.debug=ssl:handshake:verbose"

Dadurch konnte ich sehen, ob die mod_proxy_wstunnel.so, die ich geändert habe, für wss: // funktioniert oder nicht. Wenn es nicht funktionierte, würde meine Protokolldatei catalina.out Folgendes anzeigen:

javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?
http-nio-8443-exec-1, SEND TLSv1 ALERT:  fatal, description = internal_error
http-nio-8443-exec-1, WRITE: TLSv1 Alert, length = 2
http-nio-8443-exec-1, called closeOutbound()
http-nio-8443-exec-1, closeOutboundInternal()

Abschließende Gedanken

Ich verwende zwar Apache httpd 2.4.9, Ich habe gesehen, wo Backports von mod_proxy_wstunnel auf die Versionen 2.2.x angewendet werden können . Hoffentlich können meine obigen Notizen auf diese älteren Versionen angewendet werden. 

27
Tom Cawley

Wenn Sie nicht möchten, dass Apache die SSL-Verbindung abbricht (und unverschlüsselten WebSocket-Verkehr weiterleitet), der SSL jedoch auf dem endgültigen Ziel-WebSocket-Server beendet ist und und [] ausschließlich WSS für den in Apache eingehenden WebSocket-Verkehr verwenden möchten mod_proxy_connect kann möglicherweise nur über den Rohdatenverkehr eine Verbindung herstellen. Nicht sicher. Mich würde auch interessieren, ob das funktioniert.

Wenn oben nicht zutrifft, hier weitere Informationen:

In jedem Fall wird durch die Verwendung von Apache die Skalierbarkeit in Bezug auf die Anzahl gleichzeitig verwalteter WebSocket-Verbindungen stark eingeschränkt, da jede WS-Verbindung 1 Prozess/Thread für Apache beansprucht.

1
oberstet

Ich versuche dieses https://github.com/kawasima/mod_proxy_websocket zu installieren. Ich hoffe es hilft.

0
dlopezgonzalez