Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Wilkins2015-05-29 10:12:57 +0000
committerGreg Wilkins2015-05-29 10:12:57 +0000
commit4472b614b94550c167dab5c2e3f3362368d4dba0 (patch)
tree4d55d152c2ae33d18569877473a7146dbfd68384
parent0db541889bae3767d2e10c7799451807136766ff (diff)
downloadorg.eclipse.jetty.project-4472b614b94550c167dab5c2e3f3362368d4dba0.tar.gz
org.eclipse.jetty.project-4472b614b94550c167dab5c2e3f3362368d4dba0.tar.xz
org.eclipse.jetty.project-4472b614b94550c167dab5c2e3f3362368d4dba0.zip
468747 - XSS vulnerability in HttpSpiContextHandler
-rw-r--r--jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/HttpSpiContextHandler.java20
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/Response.java14
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java25
-rw-r--r--jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java68
-rw-r--r--jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java2
-rw-r--r--jetty-util/src/test/java/org/eclipse/jetty/util/StringUtilTest.java16
-rw-r--r--jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java3
-rw-r--r--jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlAppendable.java29
8 files changed, 106 insertions, 71 deletions
diff --git a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/HttpSpiContextHandler.java b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/HttpSpiContextHandler.java
index 57a5b6479f..ea32d9e542 100644
--- a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/HttpSpiContextHandler.java
+++ b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/HttpSpiContextHandler.java
@@ -29,6 +29,9 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
import com.sun.net.httpserver.Authenticator;
import com.sun.net.httpserver.Authenticator.Result;
@@ -42,7 +45,8 @@ import com.sun.net.httpserver.HttpPrincipal;
*/
public class HttpSpiContextHandler extends ContextHandler
{
-
+ public static final Logger LOG = Log.getLogger(HttpSpiContextHandler.class);
+
private HttpContext _httpContext;
private HttpHandler _httpHandler;
@@ -87,17 +91,21 @@ public class HttpSpiContextHandler extends ContextHandler
}
catch (Exception ex)
{
+ LOG.debug(ex);
PrintWriter writer = new PrintWriter(jettyHttpExchange.getResponseBody());
resp.setStatus(500);
writer.println("<h2>HTTP ERROR: 500</h2>");
writer.println("<pre>INTERNAL_SERVER_ERROR</pre>");
- writer.println("<p>RequestURI=" + req.getRequestURI() + "</p>");
-
- writer.println("<pre>");
- ex.printStackTrace(writer);
- writer.println("</pre>");
+ writer.println("<p>RequestURI=" + StringUtil.sanitizeXmlString(req.getRequestURI()) + "</p>");
+ if (LOG.isDebugEnabled())
+ {
+ writer.println("<pre>");
+ ex.printStackTrace(writer);
+ writer.println("</pre>");
+ }
+
writer.println("<p><i><small><a href=\"http://eclipse.org/jetty\">Powered by jetty://</a></small></i></p>");
writer.close();
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java
index 67992412ee..93cc88b181 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java
@@ -602,19 +602,9 @@ public class Response implements HttpServletResponse
setContentType(MimeTypes.Type.TEXT_HTML_8859_1.toString());
try (ByteArrayISO8859Writer writer= new ByteArrayISO8859Writer(2048);)
{
- if (message != null)
- {
- message= StringUtil.replace(message, "&", "&amp;");
- message= StringUtil.replace(message, "<", "&lt;");
- message= StringUtil.replace(message, ">", "&gt;");
- }
+ message=StringUtil.sanitizeXmlString(message);
String uri= request.getRequestURI();
- if (uri!=null)
- {
- uri= StringUtil.replace(uri, "&", "&amp;");
- uri= StringUtil.replace(uri, "<", "&lt;");
- uri= StringUtil.replace(uri, ">", "&gt;");
- }
+ uri=StringUtil.sanitizeXmlString(uri);
writer.write("<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html;charset=ISO-8859-1\"/>\n");
writer.write("<title>Error ");
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java
index c5123b7fd4..9591e539af 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java
@@ -39,6 +39,7 @@ import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.ByteArrayISO8859Writer;
+import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@@ -275,29 +276,7 @@ public class ErrorHandler extends AbstractHandler
if (string==null)
return;
- for (int i=0;i<string.length();i++)
- {
- char c=string.charAt(i);
-
- switch(c)
- {
- case '&' :
- writer.write("&amp;");
- break;
- case '<' :
- writer.write("&lt;");
- break;
- case '>' :
- writer.write("&gt;");
- break;
-
- default:
- if (Character.isISOControl(c) && !Character.isWhitespace(c))
- writer.write('?');
- else
- writer.write(c);
- }
- }
+ writer.write(StringUtil.sanitizeXmlString(string));
}
/* ------------------------------------------------------------ */
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java
index 07d85de3ce..e82b8c9387 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java
@@ -733,5 +733,73 @@ public class StringUtil
return s.substring(1,s.length()-1).split(" *, *");
}
+
+ public static String sanitizeXmlString(String html)
+ {
+ if (html==null)
+ return null;
+
+ int i=0;
+
+ // Are there any characters that need sanitizing?
+ loop: for (;i<html.length();i++)
+ {
+ char c=html.charAt(i);
+
+ switch(c)
+ {
+ case '&' :
+ case '<' :
+ case '>' :
+ case '\'':
+ case '"':
+ break loop;
+
+ default:
+ if (Character.isISOControl(c) && !Character.isWhitespace(c))
+ break loop;
+ }
+ }
+
+ // No characters need sanitizing, so return original string
+ if (i==html.length())
+ return html;
+
+ // Create builder with OK content so far
+ StringBuilder out = new StringBuilder(html.length()*4/3);
+ out.append(html,0,i);
+
+ // sanitize remaining content
+ for (;i<html.length();i++)
+ {
+ char c=html.charAt(i);
+
+ switch(c)
+ {
+ case '&' :
+ out.append("&amp;");
+ break;
+ case '<' :
+ out.append("&lt;");
+ break;
+ case '>' :
+ out.append("&gt;");
+ break;
+ case '\'':
+ out.append("&apos;");
+ break;
+ case '"':
+ out.append("&quot;");
+ break;
+
+ default:
+ if (Character.isISOControl(c) && !Character.isWhitespace(c))
+ out.append('?');
+ else
+ out.append(c);
+ }
+ }
+ return out.toString();
+ }
}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java
index 6fa97109a6..073072018f 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java
@@ -613,7 +613,7 @@ public abstract class Resource implements ResourceFactory, Closeable
private static String deTag(String raw)
{
- return StringUtil.replace( StringUtil.replace(raw,"<","&lt;"), ">", "&gt;");
+ return StringUtil.sanitizeXmlString(raw);
}
/* ------------------------------------------------------------ */
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/StringUtilTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/StringUtilTest.java
index 1f78960308..8c4b05f8ee 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/StringUtilTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/StringUtilTest.java
@@ -201,7 +201,8 @@ public class StringUtilTest
}
@Test
- public void testIsBlank() {
+ public void testIsBlank()
+ {
Assert.assertTrue(StringUtil.isBlank(null));
Assert.assertTrue(StringUtil.isBlank(""));
Assert.assertTrue(StringUtil.isBlank("\r\n"));
@@ -216,7 +217,8 @@ public class StringUtilTest
}
@Test
- public void testIsNotBlank() {
+ public void testIsNotBlank()
+ {
Assert.assertFalse(StringUtil.isNotBlank(null));
Assert.assertFalse(StringUtil.isNotBlank(""));
Assert.assertFalse(StringUtil.isNotBlank("\r\n"));
@@ -229,4 +231,14 @@ public class StringUtilTest
Assert.assertTrue(StringUtil.isNotBlank("."));
Assert.assertTrue(StringUtil.isNotBlank(";\n"));
}
+
+ @Test
+ public void testSanitizeHTML()
+ {
+ assertEquals(null,StringUtil.sanitizeXmlString(null));
+ assertEquals("",StringUtil.sanitizeXmlString(""));
+ assertEquals("&lt;&amp;&gt;",StringUtil.sanitizeXmlString("<&>"));
+ assertEquals("Hello &lt;Cruel&gt; World",StringUtil.sanitizeXmlString("Hello <Cruel> World"));
+ assertEquals("Hello ? World",StringUtil.sanitizeXmlString("Hello \u0000 World"));
+ }
}
diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java
index 2e814b889d..da3be6022f 100644
--- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java
+++ b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java
@@ -39,6 +39,7 @@ import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.server.HttpConnection;
+import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@@ -477,7 +478,7 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
}
else
{
- warn.append('"').append(ua.replaceAll("<", "&lt;")).append("\" ");
+ warn.append('"').append(StringUtil.sanitizeXmlString(ua)).append("\" ");
}
warn.append("requested WebSocket version [").append(version);
warn.append("], Jetty supports version");
diff --git a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlAppendable.java b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlAppendable.java
index 084f1c4f13..e6fc84c3d6 100644
--- a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlAppendable.java
+++ b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlAppendable.java
@@ -25,6 +25,8 @@ import java.io.OutputStreamWriter;
import java.util.Map;
import java.util.Stack;
+import org.eclipse.jetty.util.StringUtil;
+
public class XmlAppendable
{
private final String SPACES=" ";
@@ -82,32 +84,7 @@ public class XmlAppendable
public XmlAppendable content(String s) throws IOException
{
if (s!=null)
- {
- for (int i=0;i<s.length();i++)
- {
- char c = s.charAt(i);
- switch(c)
- {
- case '<':
- _out.append("&lt;");
- break;
- case '>':
- _out.append("&gt;");
- break;
- case '&':
- _out.append("&amp;");
- break;
- case '\'':
- _out.append("&apos;");
- break;
- case '"':
- _out.append("&quot;");
- break;
- default:
- _out.append(c);
- }
- }
- }
+ _out.append(StringUtil.sanitizeXmlString(s));
return this;
}

Back to the top