The KNVB
The KNVB

Reputation: 3844

secure websocket connection between javascript client and netty server

I am developing websocket server with netty frame work version 4.1.6. I am using the sample code from netty example site This is my server source code:

public class WebSocketServer 
{
    static final int PORT = 4466;
    public static void main(String[] args) 
    {
         final SslContext sslCtx; 
         EventLoopGroup bossGroup = new NioEventLoopGroup(1);
         EventLoopGroup workerGroup = new NioEventLoopGroup();

         try {
             SelfSignedCertificate ssc = new SelfSignedCertificate();
             sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
             ServerBootstrap b = new ServerBootstrap();
             b.group(bossGroup, workerGroup)
              .channel(NioServerSocketChannel.class)
              .handler(new LoggingHandler(LogLevel.INFO))
              .childHandler(new WebSocketServerInitializer(sslCtx));

             Channel ch = b.bind(PORT).sync().channel();

             System.out.println("Open your web browser and navigate to " +
                     "http://127.0.0.1:" + PORT + '/');

             ch.closeFuture().sync();
         } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
             bossGroup.shutdownGracefully();
             workerGroup.shutdownGracefully();
         }

    }

}

An WebSocketServerInitializer source code:

public class WebSocketServerInitializer extends ChannelInitializer<SocketChannel> 
{
    private static final String WEBSOCKET_PATH = "/websocket";
    private final SslContext sslCtx;
    public WebSocketServerInitializer(SslContext sslCtx) {
        this.sslCtx = sslCtx;
    }
    @Override
    public void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        pipeline.addLast(sslCtx.newHandler(ch.alloc()));
        pipeline.addLast(new HttpServerCodec());
        pipeline.addLast(new HttpObjectAggregator(65536));
        pipeline.addLast(new WebSocketServerCompressionHandler());
        pipeline.addLast(new WebSocketServerProtocolHandler(WEBSOCKET_PATH, null, true));
      //  pipeline.addLast(new WebSocketIndexPageHandler(WEBSOCKET_PATH));
        pipeline.addLast(new WebSocketFrameHandler());
    }
}

This is my Html code:

<html>
   <head>

      <script type="text/javascript">
         // Let us open a web socket
         var ws = null;
         function WebSocketTest()
         {
            if ("WebSocket" in window)
            {
               alert("WebSocket is supported by your Browser!");

               // Let us open a web socket
               ws = new WebSocket("wss://localhost:4466/websocket");
               ws.onopen = function()
               {
                  // Web Socket is connected, send data using send()
                  ws.send("Message to send");
                  alert("Message is sent...");
               };

               ws.onmessage = function (evt) 
               { 
                  var received_msg = evt.data;
                  alert(received_msg);
                  //alert("Message is received...");
               };

               ws.onclose = function()
               { 
                  // websocket is closed.
                  alert("Connection is closed..."); 
               };

               window.onbeforeunload = function(event) {
                  socket.close();
               };
            }

            else
            {
               // The browser doesn't support WebSocket
               alert("WebSocket NOT supported by your Browser!");
            }
         }
      </script>

   </head>
   <body>

      <div id="sse">
         <a href="javascript:WebSocketTest()">Run WebSocket</a>
      </div>
   </body>
</html>

I browse the page using Chrome browser and got the following message when I click on the link in the web page.

WebSocket connection to 'wss://localhost:4466/websocket' failed: Error in connection establishment: net::ERR_INSECURE_RESPONSE

According to some discussions here, and the netty websocket sample code, wss must be forwarded by HTTPS. However, when I change the following javascript statement in my web page:

ws = new WebSocket("wss://localhost:4466/websocket");

to

ws = new WebSocket("wss://echo.websocket.org");

It works fine. It make me confusing, Why the site echo.websocket.org can working without https? Why my server cannot? are there something missing in my server source code?

PS: the echo.websocket.org example found in the following url:

http://jsbin.com/muqamiqimu/edit?js,console

Upvotes: 0

Views: 7605

Answers (1)

Ferrybig
Ferrybig

Reputation: 18824

Your browser is failing to connect to your websocket server, because it detected it is insecure.

This happens because when the browser tries to connect to your server, it will check the SSL certificate. This certificate is basically a proof that says your server is claiming to be the authoritative server for localhost.

Your server claims this by its certificate, what in your case is signed by itself, that's basically the SelfSignedCertificate class, and it's claiming to be "example.com".

This creates 2 issues:

  • Your browser connects to localhost, but instead of getting a certificate for localhost, it gets 1 for example.com
  • Your browser does not trust the signer of the certificate to have the authority to make certificates, causing it to be rejected.

There are multiple ways to solve this:

Getting a valid certificate and hosting your application on a server

This would be the recommended solution for production, depending where you get your valid certificate, it may or may not cost money.

Bypass the certificate warning

By manually going to http://localhost:4466/ you can skip past the certificate warning, and basically this adds a 1 time exception for the certificate rule, till you restart your browser

Configuring google chrome to accept invalid certificates for localhost

While this can be insecure (but not as insecure as turning off all certificate validation), it can be a great way to test ssl on development machines.

You can turn ssl validation of for localhost by going to chrome://flags/#allow-insecure-localhost and turning that option on. Notice that you might be required to set the domain of your certificate to localhost when using this option by calling the new SelfSignedCertificate("localhost"); contructor.

Upvotes: 2

Related Questions