Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use TLS in Play!Framework WebSockets ("wss://")

I cannot use wss:// in my simple WebSocket app created with Play!Framework 2.2. It echoes the message back. The endpoint is like this

def indexWS2 = WebSocket.using[String] {
  request => {
    println("got connection to indexWS2")

    var channel: Option[Concurrent.Channel[String]] = None
    val outEnumerator: Enumerator[String] = Concurrent.unicast(c => channel = Some(c))

    // Log events to the console
    val myIteratee: Iteratee[String, Unit] = Iteratee.foreach[String] {gotString => {
      println("received: " + gotString)

      // send string back
      channel.foreach(_.push("echoing back \"" + gotString + "\""))
    }}

    (myIteratee, outEnumerator)
  }
}

and the route is described as

GET     /ws2                        controllers.Application.indexWS2

I create a connection from a JS client like this

myWebSocket = new WebSocket("ws://localhost:9000/ws2");

and everything works fine. But if I change ws:// into wss:// in order to use TLS, it fails and I get the following Netty exception:

[error] p.nettyException - Exception caught in Netty
java.lang.IllegalArgumentException: empty text

How can I make this work? Thanks.

like image 632
ticofab Avatar asked Oct 25 '13 13:10

ticofab


People also ask

Does WSS use TLS?

The wss protocol establishes a WebSocket over an encrypted TLS connection, while the ws protocol uses an unencrypted connection.

Does WebSocket require TLS?

Secure example Secure WebSocket connections improve confidentiality and also reliability because they reduce the risk of interference by bad proxies. The WSS protocol is to WS what HTTPS is to HTTP: the connection is encrypted with TLS. WSS requires TLS certificates like HTTPS.

What is TLS WebSockets?

If an encrypted WebSocket connection is used, then the use of Transport Layer Security (TLS) in the WebSocket Secure connection ensures that an HTTP CONNECT command is issued when the browser is configured to use an explicit proxy server.

Does WSS use SSL?

An SSL certificate is required for the WebSocket WSS (WebSocket Security) protocol to work in production environments that use the HTTPS protocol for the website. If your website uses an SSL certificate, you'll be required to use the WSS protocol for secure communications.


3 Answers

I really wanted to figure this out for you! But I didn't like the answer. It appears there's no Play support yet for SSL for websockets. Saw mention of it here and no sign of progress since: http://grokbase.com/t/gg/play-framework/12cd53wst9/2-1-https-and-wss-secure-websocket-clarifications-and-documentation

However, there's hope! You can use nginx as a secure websocket (wss) endpoint, to forward to a internal play app with a insecure websocket endpoint:

The page http://siriux.net/2013/06/nginx-and-websockets/ provided this explanation and sample proxy config for nginx:

Goal: WSS SSL Endpoint: forwards wss|https://ws.example.com to ws|http://ws1.example.com:10080

"The proxy is also an SSL endpoint for WSS and HTTPS connections. So the clients can use wss:// connections (e.g. from pages served via HTTPS) which work better with broken proxy servers, etc."

server {
    listen       443;
    server_name  ws.example.com;

    ssl on;
    ssl_certificate ws.example.com.bundle.crt;
    ssl_certificate_key ws.example.com.key;
    ssl_session_timeout 5m;
    ssl_protocols  SSLv2 SSLv3 TLSv1;
    ssl_ciphers  HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers   on;

    location / {

        # like above

    }
}

Nginx is so lightweight and fun. Would not hesitate to go with this option.

like image 107
sdanzig Avatar answered Sep 20 '22 00:09

sdanzig


Did you try enabling https support on the Play server? It looks like you're trying to connect to the http port using wss, that can never work, you need to enable https, and then change the URL not just to wss, but also to use the https port.

To start a Play server with ssl turned on:

activator run -Dhttps.port=9443

Then connect to wss://localhost:9443/ws2.

like image 22
James Roper Avatar answered Sep 24 '22 00:09

James Roper


wss works fine with Play 2.6.

Instead of hardcode the websocket url, you can get the url via routes:

@import play.api.mvc.RequestHeader
@import controllers.routes
@()(implicit request: RequestHeader)
<!DOCTYPE html>
<html lang="en">
    <head>
        <title>...</title>
        <script>
                var wsUri = "@routes.MyController.indexWS2().webSocketURL(secure = true)";
                var webSocket = new WebSocket(wsUri);
        //...
        </script>
    </head>
    <body>
    ...
    </body>
</html>
like image 32
qed Avatar answered Sep 20 '22 00:09

qed