使用用户名/密码和Servlet安全性保护WebSockets

RFC 6455提供了WebSockets安全注意事项的完整列表。 其中一些是在协议本身中烘焙的,其他一些则需要更多有关如何在特定服务器上实现它们的解释。 让我们谈谈协议本身内置的一些安全性:






  • HTTP请求中Origin头仅包含标识发起该请求的主体(网页,JavaScript或任何其他客户端)所需的信息(通常是发起源的方案,主机和端口)。 对于WebSocket,此标头字段包含在客户端的打开握手中。 这用于通知服务器生成WebSocket连接请求的脚本来源。 然后,服务器可以决定相应地接受或拒绝握手请求。 这样一来,服务器就可以防止使用浏览器中使用WebSocket API的脚本对WebSocket服务器进行未经授权的跨域使用。例如,如果Java EE 7 WebSocket聊天示例已部署到WildFly并通过localhost:8080 / chat /访问, Origin标头为“ http:// localhost:8080”。 非浏览器客户端可以使用Origin头来指定请求的来源。 WebSocket服务器在接收此类请求时应格外小心。
  • 来自客户端的WebSocket打开握手必须包含Sec-WebSocket-Key和Sec-WebSocket-Version HTTP标头字段。 XMLHttpRequest可用于发出HTTP请求,并允许将标头作为该请求的一部分设置为:
    xhr.onreadystatechange = function ()
    {
      if (xhr.readyState == 4 && xhr.status == 200)
      {
        document.getElementById("myDiv").innerHTML = xhr.responseText;
      }
    }
    xhr.open("GET", "http://localhost:8080", true);
    xhr.setRequestHeader("foo", "bar");
    xhr.setRequestHeader("Sec-WebSocket-Key", "myKey");
    xhr.send();

    如果XMLHttpRequest尝试设置以Sec-开头的任何头字段,则将忽略它们。 因此,恶意用户无法使用HTML和JavaScript API模拟与服务器的WebSocket连接。

除了这两种主要方法外,还可以使用任何HTTP服务器可用的客户端身份验证机制来保护WebSocket。 该技术提示将显示如何验证在WildFly上部署的Java EE 7 WebSockets。

让我们开始吧!

  • 克隆Java EE 7示例工作空间:
    git clone https://github.com/javaee-samples/javaee7-samples.git
  • “ websocket / endpoint-security”示例显示了如何从客户端启动WebSocket握手之前完成客户端身份验证。 这是通过包含以下部署描述符来触发的:
    <security-constraint>
      <web-resource-collection>
        <web-resource-name>WebSocket Endpoint</web-resource-name>
        <url-pattern>/*</url-pattern>
        <http-method>GET</http-method>
      </web-resource-collection>
      <auth-constraint>
        <role-name>g1</role-name>
      </auth-constraint>
    </security-constraint>
     
    <login-config>
      <auth-method>BASIC</auth-method>
      <realm-name>file</realm-name>
    </login-config>
     
    <security-role>
      <role-name>g1</role-name>
    </security-role>

    有关此描述符的一些关键点:

    • <url-pattern>表示将提示对此应用程序发出的任何请求进行身份验证
    • <auth-constraint>定义可以访问此资源的安全角色
    • <login-config>显示基于文件的领域与基本身份验证一起使用
    • <security-role>定义此应用程序引用的安全角色

    在我们的特定情况下,创建WebSocket连接的页面受到基本身份验证的保护。

  • 下载WildFly 8.1 ,解压缩并通过调用以下脚本来添加新用户:
    ./bin/add-user.sh -a -u u1 -p p1 -g g1

    这将在组“ g1”中添加密码为“ p1”的用户“ u1”。 此处指定的组需要匹配部署描述符中的<role-name>中定义。

  • 通过提供以下命令来部署样本:
    mvn wildfly:deploy

现在,当通过localhost:8080 / endpoint-security访问该应用程序时,将弹出一个安全对话框,如下所示:

使用用户名/密码和Servlet安全性保护WebSockets

输入“ u1”作为用户名,输入“ p1”作为密码进行身份验证。 这些凭据在部署描述符中引用的组“ g1”中定义。 任何其他凭据将继续使对话框恢复。

成功验证请求后,将建立WebSocket连接,并在浏览器中显示一条消息。

如果您只想保护WebSocket URL,请从以下位置更改URL模式:

/*

至:

/websocket

在websocket.js中,更改URL以从以下位置创建WebSocket端点:

var wsUri = "ws://" + document.location.host + document.location.pathname + "websocket";

至:

var wsUri = "ws://u1:[email protected]" + document.location.host + document.location.pathname + "websocket";

请注意,如何在URL本身中传递凭据。 从Google Chrome 38.0.2125.104开始,如果仅WebSocket URL需要身份验证,则不会出现浏览器弹出窗口。

下一技巧提示将说明如何使用wss://协议保护WebSocket的安全。

翻译自: https://www.javacodegeeks.com/2014/10/securing-websockets-using-usernamepassword-and-servlet-security.html