gpt4 book ai didi

java - 如何保护 Java EE 中的 WebSocket 端点?

转载 作者:行者123 更新时间:2023-12-01 14:09:18 24 4
gpt4 key购买 nike

我按照本教程使用 Java EE 设置 websocket 端点:

https://technology.amis.nl/2013/06/22/java-ee-7-ejb-publishing-cdi-events-that-are-pushed-over-websocket-to-browser-client/

出于显而易见的原因,在安全性方面还有一些工作要做(例如没有 SSL 和访问限制/身份验证)。

所以我的目标是通过

来提高 websocket 的安全性
  • 使用 SSL(wss://而不是 ws://) - 完成
  • 设置用户身份验证 (web.xml) - 完成
  • 实现 SSL 通信 (web.xml) - 完成
  • 使用 token 保护 websocket 连接(有限的生命周期)

My Question: How can i verify the token which I created in the LoginBean at the ServerEndpoint?

Bonus Question: Did I miss some important parts in securing websockets in Java EE?

这是我目前所拥有的:

服务器端点

import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/user/endpoint/{token}")
public class ThisIsTheSecuredEndpoint {

@OnOpen
public void onOpen(@PathParam("token") String incomingToken,
Session session) throws IOException {

//How can i check if the token is valid?

}
}

LoginBean

@ManagedBean
@SessionScoped
public class LoginBean {

public String login() {

FacesContext facesContext = FacesContext.getCurrentInstance();
HttpServletRequest request = (HttpServletRequest)facesContext.getExternalContext().getRequest();

try {
request.login("userID", "password");

HttpSession session = request.getSession();

// here we put the token in the session
session.setAttribute("token", "someVeeeeryLongRandomValue123hfgrtwpqllkiw");


} catch (ServletException e) {
facesContext.addMessage(null, new FacesMessage("Login failed."));
return "error";
}

return "home";
}

}

Javascipt

这是我想用来连接到 websocket 的代码:

// use SSL 
// retrive the token from session via EL-expression #{session.getAttribute("token")}
var wsUri = "wss://someHost.com/user/endpoint/#{session.getAttribute("token")}";
var websocket = new WebSocket(wsUri);

websocket.onerror = function(evt) { onError(evt) };

function onError(evt) {
writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
}

// For testing purposes
var output = document.getElementById("output");
websocket.onopen = function(evt) { onOpen(evt) };

function writeToScreen(message) {
output.innerHTML += message + "<br>";
}

function onOpen() {
writeToScreen("Connected to " + wsUri);
}

web-xml:

使用登录名保护“/user/*”目录并强制执行 SSL 通信

<security-constraint>
...
<web-resource-name>Secured Area</web-resource-name>
<url-pattern>pathToSecuredDicrtoy</url-pattern>
...
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
...
</security-constraint>
<login-config>
<auth-method>FORM</auth-method> ...
</login-config>

注意:我正在使用 JSF

非常感谢任何反馈。

最佳答案

您可以使用 Servlet 过滤器进行身份验证。

这是我不久前创建的用于保护聊天端点的过滤器示例。它从名为 access-token 的查询参数中提取访问 token ,并将 token 验证委托(delegate)给名为 Authenticator 的 bean。

您可以轻松适应您的需求:

/**
* Access token filter for the chat websocket. Requests without a valid access token
* are refused with a <code>403</code>.
*
* @author cassiomolin
*/
@WebFilter("/chat/*")
public class AccessTokenFilter implements Filter {

@Inject
private Authenticator authenticator;

@Override
public void init(FilterConfig filterConfig) throws ServletException {

}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {

HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;

// Extract access token from the request
String token = request.getParameter("access-token");
if (token == null || token.trim().isEmpty()) {
returnForbiddenError(response, "An access token is required to connect");
return;
}

// Validate the token and get the user who the token has been issued for
Optional<String> optionalUsername = authenticator.getUsernameFromToken(token);
if (optionalUsername.isPresent()) {
filterChain.doFilter(
new AuthenticatedRequest(
request, optionalUsername.get()), servletResponse);
} else {
returnForbiddenError(response, "Invalid access token");
}
}

private void returnForbiddenError(HttpServletResponse response, String message)
throws IOException {
response.sendError(HttpServletResponse.SC_FORBIDDEN, message);
}

@Override
public void destroy() {

}

/**
* Wrapper for a {@link HttpServletRequest} which decorates a
* {@link HttpServletRequest} by adding a {@link Principal} to it.
*
* @author cassiomolin
*/
private static class AuthenticatedRequest extends HttpServletRequestWrapper {

private String username;

public AuthenticatedRequest(HttpServletRequest request, String username) {
super(request);
this.username = username;
}

@Override
public Principal getUserPrincipal() {
return () -> username;
}
}
}

聊天端点类似于:

@ServerEndpoint("/chat")
public class ChatEndpoint {

private static final Set<Session> sessions =
Collections.synchronizedSet(new HashSet<>());

@OnOpen
public void onOpen(Session session) {
sessions.add(session);
String username = session.getUserPrincipal().getName();
welcomeUser(session, username);
}

...

}

该应用程序可用here .

关于java - 如何保护 Java EE 中的 WebSocket 端点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42644779/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com