Securing WebSockets using Username/Password and Servlet Security (Tech Tip #49)

RFC 6455 provide a complete list of security considerations for WebSockets. Some of them are baked in the protocol itself, and others need more explanation on how they can be achieved on a particular server. Lets talk about some of the security built into the protocol itself:

  • The Origin header in HTTP request includes only the information required to identify the principal (web page, JavaScript or any other client) that initiated the request (typically the scheme, host, and port of initiating origin). For WebSockets, this header field is included in the client’s opening handshake. This is used to inform server of the script origin generating the WebSocket connection request. The server may then decide to accept or reject the handshake request accordingly. This allows the server to protect against unauthorized cross-origin use of a WebSocket server by scripts using the WebSocket API in a browser.

    For example, if Java EE 7 WebSocket Chat sample is deployed to WildFly and accessed at localhost:8080/chat/ then the Origin header is “http://localhost:8080”. Non-browser clients may use the Origin header to specify the origin of the request. WebSocket servers should be careful about receiving such requests.
  • WebSocket opening handshake from client must include Sec-WebSocket-Key and Sec-WebSocket-Version HTTP header field. XMLHttpRequest can be used to make HTTP requests, and allows to set headers as part of that request as:
    If XMLHttpRequest tries to set any header fields starting with Sec- then they are ignored. So a malicious user cannot simulate a WebSocket connection to a server by using HTML and JavaScript APIs.

In addition to these two primary ways, WebSockets can be secured using client authentication mechanism available to any HTTP servers. This Tech Tip will show how to authenticate Java EE 7 WebSockets deployed on WildFly.

Lets get started!

  • Clone Java EE 7 Samples workspace:
  • The “websocket/endpoint-security” sample shows how client authentication can be done before the WebSocket handshake is initiated from the client. This is triggered by including the following deployment descriptor:
    Some key points to understand about this descriptor:

    • <url-pattern> indicates that any request made to this application will be prompted for authentication
    • <auth-constraint> defines the security role that can access this resource
    • <login-config> shows that file-based realm is used with basic authentication
    • <security-role> defines the security roles referenced by this application

    In our particular case, the page that creates the WebSocket connection is protected by basic authentication.

  • Download WildFly 8.1, unzip, and add a new user by invoking the following script:

    This will add user “u1” with password “p1” in group “g1”. The group specified here needs to match as defined in <role-name> in the deployment descriptor.

  • Deploy the sample by giving the command:

Now when the application is accessed at localhost:8080/endpoint-security then a security dialog box pops up as shown:

techtip49-browser-security-popup

Enter “u1” as the username and “p1” as the password to authenticate. These credentials are defined in the group “g1” which is referenced in the deployment descriptor. Any other credentials will keep bringing the dialog back.

As soon as the request is successfully authenticated, the WebSocket connection is established and a message is shown on the browser.

If you are interested in securing only the WebSocket URL then change the URL pattern from

to

In websocket.js, change the URL to create WebSocket endpoint from:

to

Note, how credentials are passed in the URL itself. As of Google Chrome 38.0.2125.104, a browser popup does not appear if only WebSocket URL requires authentication.

Next Tech Tip will explain how to secure WebSocket using wss:// protocol.

Be Sociable, Share!
  • Tweet

6 thoughts on “Securing WebSockets using Username/Password and Servlet Security (Tech Tip #49)

  1. Hi Arun,
    I develop a framework base on websocket, but I met problem about authentification/authorization.
    I use Tyrus, CDI and EJB in glassfish or Wildfly.
    I set security like you are described in this post.
    If I test session/client.getUserPrincipal(), it’s ok, my current user is set.
    But when I call my business component, EJB/CDI, I loose this information.
    SessionContext, and Injected Principal return ANONYMOUS.
    I can’t believe that, do you know what’s wrong in my thinking ?

    My WebSocket
    https://github.com/hhdevelopment/ocelot/blob/master/ocelot-web/src/main/java/org/ocelotds/web/OcelotEndpoint.java
    Thanks

    Francois

  2. Have you tried posting a comment to GlassFish or WildFly forums?

    Tried a simple Hello World sample with security? Some are documented at: https://github.com/javaee-samples/javaee7-samples/tree/master/websocket

    Arun

  3. Hi Arun
    In fact http request and endpoint are not in the same thread.
    I found some hack about that and I do that :
    In http request thread, I save informations about the user, and save them in websocket session. ws session != http session.
    The ws ans http session are accessible in same time in ServerEndpoint configurator.
    @ServerEndpoint(value = “/endpoint”, configurator = Configurator.class)

    Next step in the thread of business calling, I get back the user infos and set them in the current thread.

    On glassfish I do that :
    WS Configurator
    com.sun.enterprise.security.SecurityContext current = com.sun.enterprise.security.SecurityContext.getCurrent();
    In business thread :
    com.sun.enterprise.security.SecurityContext.setCurrent(subject);

    On Wildfly
    WS Configurator
    SecurityContextAssociation.getPrincipal();
    SecurityContextAssociation.getSubject();
    SecurityContextAssociation.getCredential();
    In business thread :
    final SecurityContext secuContext = SecurityContextAssociation.getSecurityContext();
    final Role roleGroup = getRoleGroup(context.getSubject());
    final Identity identity = CredentialIdentityFactory.createIdentity(context.getPrincipal(), context.getCredential(), roleGroup);
    if (null != secuContext) {
    SecurityContextUtil util = secuContext.getUtil();
    util.createSubjectInfo(identity, context.getSubject());
    }

    I tried with picketlink, but the problem was not simple too.
    Now I tried with weblogic, and it’s harder, cause not open source… LOL
    After I’m going to try with WAS libery
    Do you have an ideaabout that ?

  4. It is a puzzle type game if you are new user of this bejeweled 3 games then you must see that how this game will be played it will be help to find the actual way that how you can play.

Leave a Reply

Your email address will not be published. Required fields are marked *