You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ta...@apache.org on 2018/11/26 09:08:27 UTC
[myfaces] branch 2.2.x updated: MYFACES-4266 Ajax update fails due
to invalid characters in response XML (DoS)
This is an automated email from the ASF dual-hosted git repository.
tandraschko pushed a commit to branch 2.2.x
in repository https://gitbox.apache.org/repos/asf/myfaces.git
The following commit(s) were added to refs/heads/2.2.x by this push:
new 0938417 MYFACES-4266 Ajax update fails due to invalid characters in response XML (DoS)
0938417 is described below
commit 09384178c2c1b07618d6bfc5ad7443b1a686f281
Author: Thomas Andraschko <ta...@apache.org>
AuthorDate: Mon Nov 26 10:08:31 2018 +0100
MYFACES-4266 Ajax update fails due to invalid characters in response XML (DoS)
---
.../myfaces/context/PartialResponseWriterImpl.java | 3 +-
.../util/IllegalXmlCharacterFilterWriter.java | 86 ++++++++++++++++++++++
.../context/PartialResponseWriterImplTest.java | 40 ++++++++++
3 files changed, 128 insertions(+), 1 deletion(-)
diff --git a/impl/src/main/java/org/apache/myfaces/context/PartialResponseWriterImpl.java b/impl/src/main/java/org/apache/myfaces/context/PartialResponseWriterImpl.java
index e1113af..698bcc7 100644
--- a/impl/src/main/java/org/apache/myfaces/context/PartialResponseWriterImpl.java
+++ b/impl/src/main/java/org/apache/myfaces/context/PartialResponseWriterImpl.java
@@ -29,6 +29,7 @@ import javax.faces.context.PartialResponseWriter;
import javax.faces.context.ResponseWriter;
import org.apache.myfaces.util.CDataEndEscapeFilterWriter;
+import org.apache.myfaces.util.IllegalXmlCharacterFilterWriter;
/**
* <p/>
@@ -109,7 +110,7 @@ public class PartialResponseWriterImpl extends PartialResponseWriter
public PartialResponseWriterImpl(ResponseWriter writer)
{
- super(writer);
+ super(writer.cloneWithWriter(new IllegalXmlCharacterFilterWriter(writer)));
}
@Override
diff --git a/impl/src/main/java/org/apache/myfaces/util/IllegalXmlCharacterFilterWriter.java b/impl/src/main/java/org/apache/myfaces/util/IllegalXmlCharacterFilterWriter.java
new file mode 100644
index 0000000..f7011e3
--- /dev/null
+++ b/impl/src/main/java/org/apache/myfaces/util/IllegalXmlCharacterFilterWriter.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.util;
+
+import java.io.FilterWriter;
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * There are unicodes outside the ranges defined in the
+ * <a href="https://www.w3.org/TR/REC-xml/#charsets">XML 1.0 specification</a> that break XML parsers
+ * and therefore must be filtered out when writing partial responses. Otherwise this may lead to
+ * Denial of Service attacks.
+ * @see https://issues.apache.org/jira/browse/MYFACES-4266
+ */
+public class IllegalXmlCharacterFilterWriter extends FilterWriter
+{
+ public IllegalXmlCharacterFilterWriter(Writer out)
+ {
+ super(out);
+ }
+
+ @Override
+ public void write(int c) throws IOException
+ {
+ super.write(xmlEncode((char) c));
+ }
+
+ @Override
+ public void write(char[] cbuf, int off, int len) throws IOException
+ {
+ super.write(xmlEncode(cbuf), off, len);
+ }
+
+ @Override
+ public void write(String str, int off, int len) throws IOException
+ {
+ super.write(new String(xmlEncode(str.toCharArray())), off, len);
+ }
+
+ private char[] xmlEncode(char[] ca)
+ {
+ for (int i = 0; i < ca.length; i++)
+ {
+ ca[i] = xmlEncode(ca[i]);
+ }
+ return ca;
+ }
+
+ private char xmlEncode(char c)
+ {
+ if (Character.isSurrogate(c))
+ {
+ return ' ';
+ }
+ if (c == '\u0009' || c == '\n' || c == '\r')
+ {
+ return c;
+ }
+ if (c > '\u0020' && c < '\uD7FF')
+ {
+ return c;
+ }
+ if (c > '\uE000' && c < '\uFFFD')
+ {
+ return c;
+ }
+ return ' ';
+ }
+}
diff --git a/impl/src/test/java/org/apache/myfaces/context/PartialResponseWriterImplTest.java b/impl/src/test/java/org/apache/myfaces/context/PartialResponseWriterImplTest.java
index 4a19219..b876cbf 100644
--- a/impl/src/test/java/org/apache/myfaces/context/PartialResponseWriterImplTest.java
+++ b/impl/src/test/java/org/apache/myfaces/context/PartialResponseWriterImplTest.java
@@ -298,7 +298,47 @@ public class PartialResponseWriterImplTest extends AbstractJsfTestCase {
}
}
+ public void testWriteIllegalXmlUnicodeCharacters() {
+ _writer = createTestProbe();
+ try {
+ String illegalChars = " \u0001\u0002\u0003\u0004\u0005\u0006\u000B\f\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F \uD7FF\uDBFF\uDC00\uE000��";
+ String legalChars = "foo";
+ _writer.write(illegalChars + legalChars);
+ assertEquals("All illegal XML unicode characters should have been replaced by spaces", legalChars, _contentCollector.toString().trim());
+
+ } catch (IOException e) {
+ fail(e.toString());
+ }
+ }
+
+ public void testWriteTextIllegalXmlUnicodeCharacters() {
+ _writer = createTestProbe();
+ try {
+ String illegalChars = " \u0001\u0002\u0003\u0004\u0005\u0006\u000B\f\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F \uD7FF\uDBFF\uDC00\uE000��";
+ String legalChars = "foo";
+ _writer.writeText(illegalChars + legalChars, null);
+ assertEquals("All illegal XML unicode characters should have been replaced by spaces", legalChars, _contentCollector.toString().trim());
+
+ } catch (IOException e) {
+ fail(e.toString());
+ }
+ }
+ public void testWriteAttributeIllegalXmlUnicodeCharacters() {
+ _writer = createTestProbe();
+ try {
+ String illegalChars = " \u0001\u0002\u0003\u0004\u0005\u0006\u000B\f\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F \uD7FF\uDBFF\uDC00\uE000��";
+ String legalChars = "foo";
+ _writer.startElement(legalChars, null);
+ _writer.writeAttribute(legalChars, illegalChars + legalChars, null);
+ _writer.endElement(legalChars);
+ assertTrue("All illegal XML unicode characters should have been replaced by spaces",
+ _contentCollector.toString().matches("<:X: :X:=\"[ ]+:X:\"></:X:>".replace(":X:", legalChars)));
+
+ } catch (IOException e) {
+ fail(e.toString());
+ }
+ }
/**
* creates a new test probe (aka response writer)