how to secure websockets with netty - websocket

I want to use netty for websockets with TLS enabled and using the (wss://) schema.
So I figured I should work like this:
the WebSocketServerHandler should now extend theSslHandler.
So I basically only have to set up an SSLEngine wihin the WebSocketServerPipelineFactory.
I can than pass the engine to the secure handler:
SSLEngine sslEngine = SSLContext.getDefault().createSSLEngine();
pipeline.addLast("handler", new WebSocketServerHandler(sslEngine));
Is this approach in general the right one and (if the approach is correct) - how do I set up the SSLEngine (I've my certificate & private/public keys as files available). I couldn't find any example!
Thanks.

Netty has examples :-)
Netty Master
https://github.com/netty/netty/tree/master/example/src/main/java/io/netty/example/http/websocketx/sslserver
Netty 3.x Branch
https://github.com/netty/netty/tree/3/src/main/java/org/jboss/netty/example/http/websocketx/sslserver

Related

haproxy per backend ciphers/cipher suites

I think the answer to this is no, but don’t understand why this feature is not available, I’d like to configure a list of ciphers on a per backend basis i.e to be able to use ssl-default-server-ciphers in each backend section rather than having to use ciphers on each server line. I don’t want to use ssl-default-server-ciphers in the global section as each backend can have a different set of ciphers.
I can't seem to add formatted text in comment reply, so I'll address the response below by clarifying the question here. Backends DO have an option to specify ciphers, here is an edited example from one of my configs:
backend https_be
server 10.255.2.5 10.255.2.5:443 ssl ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256
server 10.255.2.6 10.255.2.6:443 ssl ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256
What I'd like to be able to do, and would be much cleaner is:
backend https_be
option ssl-default-server-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256
server 10.255.2.5 10.255.2.5:443 ssl
server 10.255.2.6 10.255.2.6:443 ssl
But haproxy does not seem to support this, I don't know why, it would be a useful think to do AND make config files easier to read. As for the comment on frontend reference I did not mention frontends so a little confused over that comment. It is true the same issue applies to bind on frontend, but I tried to keep it simple and illustrate the point with a backend example.
I’d like to configure a list of ciphers on a per backend basis
A backend have no cipher option. Do you mean the bind option ciphers ?
I don’t want to use ssl-default-server-ciphers in the global section as each backend can have a different set of ciphers.
Well then don't set ssl-default-server-ciphers and define the ciphers on the server line.
A backend have servers which have ciphers as option. Please don't mix the keywords with what you want to do.
frontend and listen => have bind option
backend have no bind option and therefore no ciphers parameter!
This is explained in the Proxies section of the documentation.

how does websocketpp handle connections when set_tls_init_handler is not set?

I see that I have to define an on_tls_init and have the set_tls_init_handler to point to this on_tls_init for secure connections. What happens when set_tls_init_handler is not set? Does webscoketpp go head with the connection over ws:// instead of wss:// or is the connection dropped?
WebSocket++'s transport security behavior is based on which config your endpoint uses. If your endpoint is configured to be secure, i.e. using a config, like websocketpp::config::asio whose transport socket type performs TLS encryption then not defining a tls init handler (or not returning a valid TLS context from it) will result in connections failing with an invalid_tls_context error.
If you want plain/unencrypted/"ws://" connections you should use an endpoing config that does not perform TLS encryption (for example websocketpp::config::asio_no_tls). An endpoint compiled with that config will ignore the tls handler.

Change path of RabbitMQ WebSocket MQTT endpoint?

I am running a RabbitMQ instance that provides MQTT over websockets via the rabbitmq_web_mqtt plugin.
For legacy reasons, I need to support a non-default WebSocket URL.
I saw in the documentation it is possible to change the port via the { port, 1234 } config, but I could not find any way to change the WebSocket URL. It is currently set to the default path of /ws
Is it possible to change the WebSocket URL without modifying the plugin?
This has been made configurable back September 2018. See already mentioned ticket.
Add line:
# echo 'web_mqtt.ws_path = /mqtt' >> /etc/rabbitmq/rabbitmq.conf
# service rabbitmq-server restart
Now being accessible by (compliant) MQTT Clients. For instance at:
ws://192.168.210.84:15675/mqtt
UPDATE: RabbitMQ now allows configuration of the WebSocket URL. See this answer.
After some research, I found out that the path is not configurable

mod_proxy_wstunnel - Mac OS X 10.11.6, Apache 2.4.18

I've been trying unsuccessfully for a few days to setup a reverse proxy to a localhost websocket url.
ProxyPass /chat/stream/ wss://localhost:8000/chat/stream/
ProxyPassReverse /chat/stream/ wss://localhost:8000/chat/stream/
I get an error in the apache error_log that reads:
No protocol handler was valid for the URL /chat/stream/. If you are
using a DSO version of mod_proxy, make sure the proxy submodules are
included in the configuration using LoadModule.
I have read countless pages via google of people using this method so I wonder if there is some issue in our setup/install of Apache that ships with Server.app 5.2?
I have all the standard modules loaded in httpd_server_app.conf
mod_proxy
mod_proxy_wstunnel
mod_proxy_http
...
Can anyone shed some light on this?
Thanks
Adam
In case someone finds themselves in a similar situation here is how I got ​Web​Socket connections working via Apache​ in MacOS Server 5.2​.
And the solution ​i​s simple.
The short version:​
​I use MacOS Server 5.2 (ships with Apache 2.4.23) to run a python Django application via the mod_wsgi module.
I had been trying to setup proxypass and wstunnel​ in MacOS 10.12 & Server 5.2 to handle websocket connections via an ASGI interface server called Daphne running on localhost on port 8001.​
I wanted to reverse proxy any WebSocket connection to wss://myapp.local/chat/stream/ to ws://localhost:8001/chat/stream/
​From what I had read on all the forums and mailing lists that I had scoured was to simply make some proxypass definitions in the appropriate virtual host and make sure that the mod_proxy and mod_proxy_wstunnel modules were loaded and it would work.
Long story short - from what I understand all ​of ​this trouble came down to MacOS Server 5 and one major change:
"A single instance of httpd runs as a reverse proxy, called the Service Proxy, and several additional instances of httpd run behind that proxy to support specific HTTP-based services, including an instance for the Websites service."
All I need​ed​ to do​ to proxy the websocket connection​ was the following:
in: /Library/Server/Web/Config/Proxy/apache_serviceproxy.conf
​Add (around line 297 (in the section about user websites, webdav):
ProxyPass / http://localhost:8001/
ProxyPassReverse / http://localhost:8001/
RewriteEngine on
RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
RewriteCond %{HTTP:CONNECTION} ^Upgrade$ [NC]
RewriteRule .* ws://localhost:8001%{REQUEST_URI} [P]
​I then kicked over the service proxy:
sudo launchctl unload -w /Applications/Server.app/Contents/ServerRoot/System/Library/LaunchDaemons/com.apple.serviceproxy.plist
sudo launchctl load -w /Applications/Server.app/Contents/ServerRoot/System/Library/LaunchDaemons/com.apple.serviceproxy.plist
​And the web socket connections ​were instantly working!
The long version:​
For many weeks I have been trying to get WebSocket connections functioning with Apache and Andrew Godwin's Django Channels project in an app I am developing.
Django Channels is
"a project to make Django able to handle more than just plain HTTP requests, including WebSockets and HTTP2, as well as the ability to run code after a response has been sent for things like thumbnailing or background calculation."
My interest in Django Channels came from my requirement of a chat system in my webapp. After watching a several of Andrew's demos on youtube and having read through the docs and eventually installing Andrew's demo django channels project I figured I would be able to get this working in production on our MacOS Server.
The current release of MacOS 10.12 and Server 5.2 ships with Apache 2.4.23. This comes with the necessary mod_proxy_wstunnel module to be able to proxy WebSocket connections (ws:// and secure wss://) in Apache and is already loaded in the server config file:
/Library/Server/Web/Config/apache2/httpd_server_app.conf
Daphne is Andrew's ASGI interface server that supports WebSockets & long-poll HTTP requests. WSGI does not.
With Daphne running on localhost on a port that MacOS isn't occupying (I went with 8001), the idea was to get Apache to reverse proxy certain requests to Daphne.
Daphne can be run on a specified port (8001 in this example) like so (-v2 for more verbosity):
daphne -p 8001 yourapp.asgi:channel_layer -v2
I wanted Daphne to handle only the web socket connections (as I use currently depend on some apache modules for serving media such as mod_xsendfile). In my case the websocket connection was via /chat/stream/ based on Andrew's demo project.
From what I had read in MacOS Server's implementation of Apache the idea is to declare these proxypass commands inside the virtual host files of your "sites" in: /Library/Server/Web/Config/apache2/sites/
In config files such as: 0000_127.0.0.1_34543_.conf
I did also read that any customisation for web apps running on MacOS Server should be made to the plist file for the required web app in: /Library/Server/Web/Config/apache2/webapps/
In a plist file such as: com.apple.webapp.wsgi.plist
Anyway...
I edited the 0000_127.0.0.1_34543_.conf file adding:
ProxyPass /chat/stream/ ws://localhost:8001/
ProxyPassReverse /chat/stream/ ws://localhost:8001/
Eager to test out my first web socket chat connection I refreshed the page only to see an error printed in the apache log:
No protocol handler was valid for the URL /chat/stream/. If you are using a DSO version of mod_proxy, make sure the proxy submodules are included in the configuration using LoadModule.
I had read of many people finding a solution at least with Apache on Ubuntu or a custom install on MacOS.
I even tried installing Apache using Brew and when that didn't work I almost proceeded to install nginx.
After countless hours/days of googling I reached to the Apache mailing list for some help with this error. Yann Ylavic was very generous with his time and offered me various ideas on how to get it going. After trying the following:
SetEnvIf Request_URI ^/chat/stream/ is_websocket
RequestHeader set Upgrade WebSocket env=is_websocket
ProxyPass /chat/stream/ ws://myserver.local:8001/chat/stream/
I noticed that the interface server on port 8001 Daphne was starting to receive ws connections!
However in the client browser it was logging:
"Error during WebSocket handshake: 'Upgrade' header is missing"
From what I could see mod_dumpio was logging that the "Connection: Upgrade" and "Upgrade: WebSocket" headers were being sent as part of the web socket handshake:
mod_dumpio: dumpio_in (data-HEAP): HTTP/1.1 101 Switching Protocols\r\nServer: AutobahnPython/0.17.1\r\nUpgrade: WebSocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: 17WYrMeMS8a4ImHpU0gS3/k0+Cg=\r\n\r\n
mod_dumpio.c(164): [client 127.0.0.1:63944] mod_dumpio: dumpio_out
mod_dumpio.c(58): [client 127.0.0.1:63944] mod_dumpio: dumpio_out (data-TRANSIENT): 160 bytes
mod_dumpio.c(100): [client 127.0.0.1:63944] mod_dumpio: dumpio_out (data-TRANSIENT): HTTP/1.1 101 Switching Protocols\r\nServer: AutobahnPython/0.17.1\r\nUpgrade: WebSocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: 17WYrMeMS8a4ImHpU0gS3/k0+Cg=\r\n\r\n
However the client browser showed nothing in the response headers.
I was more stumped than ever.
I explored the client side jQuery framework as well as the the Django channels & autobahn module to see if perhaps something was amiss, and then revised my own app and various combinations of suggestions about Apache and it's module. But nothing stood out to me.
​Then I reread the ReadMe.txt inside the apache2 dir: /Library/Server/Web/Config/apache2/ReadMe.txt
"​Special notes about the web proxy architecture in Server application
5.0:
This version of Server application contains a revised architecture for all HTTP-based services. In previous versions there was a single instance of httpd acting as a reverse proxy for Wiki, Profile, and Calendar/Address services, and also acting as the Websites service.​​ With this version, there is a major change: A single instance of httpd runs as a reverse proxy, called the Service Proxy, and several additional instances of httpd run behind that proxy to support specific HTTP-based services, including an instance for the Websites service.
Since the httpd instance for the Websites service is now behind a reverse proxy, or Service Proxy, note the following: ​... It is only the external Service Proxy httpd instance that listens on TCP ports 80 and 443; it proxies HTTP requests and responses to Websites and other HTTP-based services. ​... ​"​
​I wondered if thus ServiceProxy had somet​hing to do with it. I had a look over: /Library/Server/Web/Config/Proxy/apache_serviceproxy.conf
and noticed a comment - "# The user websites, and webdav"​.
I figured it wouldn't hurt to try adding the proxypass definitions & rewrite rules that people had suggested on the forums as their solution.
ProxyPass / http://localhost:8001/
ProxyPassReverse / http://localhost:8001/
RewriteEngine on
RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
RewriteCond %{HTTP:CONNECTION} ^Upgrade$ [NC]
RewriteRule .* ws://localhost:8001%{REQUEST_URI} [P]
​Sure enough after restarting the ServiceProxy it all started to work!​
Adam
Take a look at the ReadMe.txt file in /Library/Server/Web/Config/apache2/
It writes about the new proxy service where requests first go to an http server running on port 80 and 443, which are then forwarded to internal ports 34580 and 34543.
For the wstunnel module there's a conflict with the mod proxy module, where mod proxy will strip out tunnel headers (https://lists.gt.net/apache/users/393509). I confirmed this by changing the LogFormat in apache_serviceproxy.conf by adding to LogFormat
c:\"%{Connection}i\" u:\"%{Upgrade}i\"
I did the same in httpd_server_app.conf and could see the Connection and Upgrade websocket headers were being removed before getting to my webapp.
The fix was merely to add a file in /Library/Server/Web/Config/Proxy for my application. Look at the last line in apache_serviceproxy.conf to see the expected naming format. In my case the file is called apache_serviceproxy_customsites_ws.conf
The contents:
ProxyPass /ws/ ws://localhost:34543/ws/
ProxyPassReverse /ws/ ws://localhost:34543/ws/
This will forward the ws request to the expected internal https port 34543 and retain the headers. You must forward it to 34543 or 34580. And also note the path is included so that it can be picked up in the next step.
Then, in my webapp_script (the include file for my webapp) I have:
ProxyPass "/ws/" "ws://localhost:61614/"
ProxyPassReverse "/ws/" "ws://localhost:61614/"
This forwards the request to my websocket server running on port 61614.
With that, it's now working as expected.
In addition to what #adamteale mentioned in his answer (the TL;DR) version, I also had to add
ProxyPreserveHost On
in my apache virtual host config. Without this, Daphne wasn't returning back any response. Perhaps it was, but it wasn't being sent back to the client.
The only other unresolved issue for my setup is that daphne isn't handling wss connection. Either Apache isn't terminating SSL for wss or something else is happening. It does terminate SSL for all other http requests. However, that question is for another thread. I will raise it as soon as I am done with more research on it.
Note: Couldn't add comments to Adam's answer due to MyCurrentRep < 50

Pound SSL Ciphers and Firefox Issue

I am fairly new to Pound cfg and SSL in general and working on learning. Tried a few things I found on Google related to setting Ciphers but they failed.
We are having an issue with Firefox after setting Ciphers in Pound to not allow SSLv3. Firefox tells customers that the system is not setup properly, so it is blocking them. Here is what I am trying to do.
Disallow SSLv3, SSLv2 via Pound Cfg file. Here is what I have tried:
Ciphers "All:!SSLv2:!SSLv3"
We are using SHA2 through Godaddy for Cert and SHA256 for key. When I test via https://dev.ssllabs.com/ssltest/ we get a giant F. Any ideas?
Any and all help is greatly appreciated. Thanks!
"Ciphers" is used to configure the cipher suites, not the SSL/TLS protocols. According to the man page, you want to do this:
Disable SSLv3
Note that Disable works by disabling that protocol and all lesser protocols, so disabling SSLv3 also disables SSLv2 along with it.
You will probably want to configure Ciphers as well. Exactly how you configure it depends on what browsers and user agents you want to support, but you can get started with:
Ciphers: "EECDH+AESGCM:AES128+EECDH"

Resources