forked from pool/eclipse
- Security fix: [bsc#1183728, CVE-2020-27225]
* The Help Subsystem does not authenticate active help requests
to the local help web server, allowing an unauthenticated local
attacker to issue active help commands to the associated Eclipse
Platform process or Eclipse Rich Client Platform process.
- Add eclipse-CVE-2020-27225.patch
OBS-URL: https://build.opensuse.org/request/show/879972
OBS-URL: https://build.opensuse.org/package/show/Java:packages/eclipse?expand=0&rev=77
225 lines
10 KiB
Diff
225 lines
10 KiB
Diff
From 213812355860e3732e1b28e620df31db8ff160aa Mon Sep 17 00:00:00 2001
|
|
From: Andrew Johnson
|
|
Date: Mon, 15 Mar 2021 20:53:01 +0530
|
|
Subject: 569855: Fix for Eclipse live help. - Use tokens - Backport to
|
|
R4_15_maintenance branch
|
|
|
|
Index: eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.base/src/org/eclipse/help/internal/base/BaseHelpSystem.java
|
|
===================================================================
|
|
--- eclipse-4.15.orig/eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.base/src/org/eclipse/help/internal/base/BaseHelpSystem.java
|
|
+++ eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.base/src/org/eclipse/help/internal/base/BaseHelpSystem.java
|
|
@@ -59,6 +59,7 @@ public final class BaseHelpSystem {
|
|
private IBrowser browser;
|
|
private IBrowser internalBrowser;
|
|
private HelpDisplay helpDisplay = null;
|
|
+ private String liveHelpToken = null;
|
|
|
|
private BaseHelpSystem() {
|
|
super();
|
|
@@ -350,4 +351,29 @@ public final class BaseHelpSystem {
|
|
}
|
|
}
|
|
|
|
+ /**
|
|
+ * Check supplied token against stored token. Clears the stored token if
|
|
+ * successful.
|
|
+ *
|
|
+ * @param helpSessionToken
|
|
+ * @return true if match successful
|
|
+ */
|
|
+ public boolean matchOnceLiveHelpToken(String helpSessionToken) {
|
|
+ /*
|
|
+ * @FIXME - should we use a constant time comparison, and store/compare a
|
|
+ * cryptographic hash?
|
|
+ */
|
|
+ if (liveHelpToken != null && liveHelpToken.equals(helpSessionToken)) {
|
|
+ // Enforce one-time use.
|
|
+ liveHelpToken = null;
|
|
+ return true;
|
|
+ } else {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public void setLiveHelpToken(String helpSessionToken) {
|
|
+ liveHelpToken = helpSessionToken;
|
|
+ }
|
|
+
|
|
}
|
|
Index: eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.base/src/org/eclipse/help/internal/base/HelpDisplay.java
|
|
===================================================================
|
|
--- eclipse-4.15.orig/eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.base/src/org/eclipse/help/internal/base/HelpDisplay.java
|
|
+++ eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.base/src/org/eclipse/help/internal/base/HelpDisplay.java
|
|
@@ -15,6 +15,8 @@ package org.eclipse.help.internal.base;
|
|
|
|
import java.io.UnsupportedEncodingException;
|
|
import java.net.URLEncoder;
|
|
+import java.nio.charset.StandardCharsets;
|
|
+import java.util.UUID;
|
|
|
|
import org.eclipse.core.runtime.CoreException;
|
|
import org.eclipse.core.runtime.IConfigurationElement;
|
|
@@ -196,6 +198,12 @@ public class HelpDisplay {
|
|
String topic = helpURL.substring("topic=".length()); //$NON-NLS-1$
|
|
helpURL = getHelpDisplay().getHelpForTopic( topic, WebappManager.getHost(), WebappManager.getPort());
|
|
}
|
|
+ String basehelp = getBaseURL();
|
|
+ if (BaseHelpSystem.getMode() != BaseHelpSystem.MODE_INFOCENTER && helpURL.startsWith(basehelp)) {
|
|
+ String sessid = UUID.randomUUID().toString();
|
|
+ BaseHelpSystem.getInstance().setLiveHelpToken(sessid);
|
|
+ helpURL += (helpURL.indexOf('?') < 0 ? '?' : '&') + "token=" + sessid; //$NON-NLS-1$
|
|
+ }
|
|
|
|
BaseHelpSystem.getHelpBrowser(forceExternal)
|
|
.displayURL(helpURL);
|
|
Index: eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.webapp/advanced/livehelp_js.jsp
|
|
===================================================================
|
|
--- eclipse-4.15.orig/eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.webapp/advanced/livehelp_js.jsp
|
|
+++ eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.webapp/advanced/livehelp_js.jsp
|
|
@@ -47,7 +47,15 @@ function liveActionInternal(topHelpWindo
|
|
url=url.substring(0, i+1);
|
|
var encodedArg=encodeURIComponent(argument);
|
|
url=url+"livehelp/?pluginID="+pluginId+"&class="+className+"&arg="+encodedArg+"&nocaching="+Math.random();
|
|
-
|
|
+ <%
|
|
+ Object token = request.getSession().getAttribute("LSESSION"); //$NON-NLS-1$
|
|
+ // Validate token to protect against XSS
|
|
+ if (token instanceof String && ((String)token).matches("[a-z0-9-]{36}")) {//$NON-NLS-1$) {
|
|
+ %>
|
|
+ url=url+"&token=<%=token%>";
|
|
+ <%
|
|
+ }
|
|
+ %>
|
|
// we need to find the toolbar frame.
|
|
// to do: cleanup this, including the location of the hidden livehelp frame.
|
|
var toolbarFrame = topHelpWindow.HelpFrame.ContentFrame.ContentToolbarFrame;
|
|
Index: eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.webapp/index.jsp
|
|
===================================================================
|
|
--- eclipse-4.15.orig/eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.webapp/index.jsp
|
|
+++ eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.webapp/index.jsp
|
|
@@ -12,9 +12,11 @@
|
|
IBM Corporation - initial API and implementation
|
|
--%>
|
|
<%@ page import="org.eclipse.help.internal.webapp.data.*" errorPage="/advanced/err.jsp" contentType="text/html; charset=UTF-8"%>
|
|
+<%@ page import="java.util.UUID" %>
|
|
+<%@ page import="org.eclipse.help.internal.base.BaseHelpSystem" %>
|
|
<%
|
|
request.setCharacterEncoding("UTF-8");
|
|
- ServerState.webappStarted(application,request, response);
|
|
+ ServerState.webappStarted(application,request, response);
|
|
// Read the scope parameter
|
|
RequestScope.setScopeFromRequest(request, response);
|
|
LayoutData data = new LayoutData(application,request, response);
|
|
@@ -33,7 +35,22 @@
|
|
</body>
|
|
</html>
|
|
<%
|
|
- }else {
|
|
+ } else {
|
|
+ // For live help
|
|
+ String token = request.getParameter("token"); //$NON-NLS-1$
|
|
+ if (token != null && token.matches("[a-z0-9-]{36}")) { //$NON-NLS-1$
|
|
+ if (BaseHelpSystem.getInstance().matchOnceLiveHelpToken(token)) {
|
|
+ // Only one session can grab this
|
|
+ if (request.getSession().getAttribute("XSESSION") == null) { //$NON-NLS-1$
|
|
+ String token2 = UUID.randomUUID().toString();
|
|
+ request.getSession().setAttribute("XSESSION", token2); //$NON-NLS-1$
|
|
+ int port = request.getLocalPort();
|
|
+ response.addHeader("Set-Cookie", "XSESSION-" + port + "=" + token2 + "; HttpOnly; SameSite=Strict"); //$NON-NLS-1 //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
|
|
+ String token3 = UUID.randomUUID().toString();
|
|
+ request.getSession().setAttribute("LSESSION", token3); //$NON-NLS-1$
|
|
+ }
|
|
+ }
|
|
+ }
|
|
request.getRequestDispatcher("/advanced/index.jsp" + data.getQuery()).forward(request, response);
|
|
}
|
|
%>
|
|
Index: eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.webapp/src/org/eclipse/help/internal/webapp/data/LayoutData.java
|
|
===================================================================
|
|
--- eclipse-4.15.orig/eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.webapp/src/org/eclipse/help/internal/webapp/data/LayoutData.java
|
|
+++ eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.webapp/src/org/eclipse/help/internal/webapp/data/LayoutData.java
|
|
@@ -46,6 +46,11 @@ public class LayoutData extends RequestD
|
|
|
|
// initialize the query string
|
|
String qs = request.getQueryString();
|
|
+ // Remove any live help token
|
|
+ if (qs != null) {
|
|
+ qs = qs.replaceFirst("^token=[a-z0-9-]{36}", ""); //$NON-NLS-1$ //$NON-NLS-2$
|
|
+ qs = qs.replaceFirst("&token=[a-z0-9-]{36}", ""); //$NON-NLS-1$ //$NON-NLS-2$
|
|
+ }
|
|
if (qs != null && qs.length() > 0)
|
|
query = "?" + qs; //$NON-NLS-1$
|
|
}
|
|
Index: eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.webapp/src/org/eclipse/help/internal/webapp/servlet/LiveHelpServlet.java
|
|
===================================================================
|
|
--- eclipse-4.15.orig/eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.webapp/src/org/eclipse/help/internal/webapp/servlet/LiveHelpServlet.java
|
|
+++ eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.webapp/src/org/eclipse/help/internal/webapp/servlet/LiveHelpServlet.java
|
|
@@ -14,8 +14,8 @@
|
|
package org.eclipse.help.internal.webapp.servlet;
|
|
|
|
import java.io.IOException;
|
|
-
|
|
import javax.servlet.ServletException;
|
|
+import javax.servlet.http.Cookie;
|
|
import javax.servlet.http.HttpServlet;
|
|
import javax.servlet.http.HttpServletRequest;
|
|
import javax.servlet.http.HttpServletResponse;
|
|
@@ -51,6 +51,45 @@ public class LiveHelpServlet extends Htt
|
|
return;
|
|
}
|
|
req.setCharacterEncoding("UTF-8"); //$NON-NLS-1$
|
|
+ String sessionid = req.getSession().getId();
|
|
+ Cookie cookies[] = req.getCookies();
|
|
+ boolean jsessOK = false;
|
|
+ boolean xsessOK = false;
|
|
+ boolean lsessOK = false;
|
|
+ // Unique session ID per help server
|
|
+ int port = req.getLocalPort();
|
|
+ String xsessname = "XSESSION-" + port; //$NON-NLS-1$
|
|
+ if (cookies != null) {
|
|
+ for (Cookie cookie : cookies) {
|
|
+ if (cookie.getName().equals("JSESSIONID")) {//$NON-NLS-1$
|
|
+ if (sessionid.length() >= 30 &&
|
|
+ cookie.getValue().startsWith(sessionid)) {
|
|
+ jsessOK = true;
|
|
+ }
|
|
+ }
|
|
+ if (cookie.getName().equals(xsessname)) {
|
|
+ if (cookie.getValue().equals(req.getSession().getAttribute("XSESSION"))) { //$NON-NLS-1$
|
|
+ xsessOK = true;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ String token = req.getParameter("token"); //$NON-NLS-1$
|
|
+ if (token != null && token.equals(req.getSession().getAttribute("LSESSION"))) { //$NON-NLS-1$
|
|
+ lsessOK = true;
|
|
+ }
|
|
+ if (!jsessOK) {
|
|
+ resp.sendError(HttpServletResponse.SC_FORBIDDEN, "JSESSIONID"); //$NON-NLS-1$
|
|
+ return;
|
|
+ }
|
|
+ if (!lsessOK) {
|
|
+ resp.sendError(HttpServletResponse.SC_FORBIDDEN, "token"); //$NON-NLS-1$
|
|
+ return;
|
|
+ }
|
|
+ if (!xsessOK) {
|
|
+ resp.sendError(HttpServletResponse.SC_FORBIDDEN, xsessname);
|
|
+ return;
|
|
+ }
|
|
String pluginID = req.getParameter("pluginID"); //$NON-NLS-1$
|
|
if (pluginID == null)
|
|
return;
|
|
@@ -59,6 +98,11 @@ public class LiveHelpServlet extends Htt
|
|
return;
|
|
String arg = req.getParameter("arg"); //$NON-NLS-1$
|
|
BaseHelpSystem.runLiveHelp(pluginID, className, arg);
|
|
+ /*
|
|
+ * @FIXME Should runLiveHelp return an error if the plugin/class is wrong
|
|
+ * so a SC_BAD_REQUEST can be returned? Or does this reveal too much?
|
|
+ */
|
|
+ resp.setStatus(HttpServletResponse.SC_ACCEPTED);
|
|
}
|
|
/**
|
|
*
|