Modified: trunk/LayoutTests/ChangeLog (195072 => 195073)
--- trunk/LayoutTests/ChangeLog 2016-01-14 21:31:05 UTC (rev 195072)
+++ trunk/LayoutTests/ChangeLog 2016-01-14 21:37:49 UTC (rev 195073)
@@ -1,3 +1,17 @@
+2016-01-14 Daniel Bates <[email protected]>
+
+ [XSS Auditor] Partial bypass when web server collapses path components
+ https://bugs.webkit.org/show_bug.cgi?id=152872
+
+ Reviewed by Brent Fulgham.
+
+ Merged from Blink (patch by Tom Sepez <[email protected]>):
+ <https://src.chromium.org/viewvc/blink?revision=167610&view=revision>
+
+ * http/tests/security/xssAuditor/embed-tag-in-path-unterminated-expected.txt: Added.
+ * http/tests/security/xssAuditor/embed-tag-in-path-unterminated.html: Added.
+ * http/tests/security/xssAuditor/intercept/.htaccess:
+
2016-01-14 Zalan Bujtas <[email protected]>
[iOS Simulator] fast/table/003.html failing
Added: trunk/LayoutTests/http/tests/security/xssAuditor/embed-tag-in-path-unterminated-expected.txt (0 => 195073)
--- trunk/LayoutTests/http/tests/security/xssAuditor/embed-tag-in-path-unterminated-expected.txt (rev 0)
+++ trunk/LayoutTests/http/tests/security/xssAuditor/embed-tag-in-path-unterminated-expected.txt 2016-01-14 21:37:49 UTC (rev 195073)
@@ -0,0 +1,4 @@
+CONSOLE MESSAGE: line 4: The XSS Auditor refused to execute a script in 'http://localhost:8000/security/xssAuditor/intercept/echo-intertag.pl/%3Cembed%20height=%22500%22src=%22https://127.0.0.1:8443/security/xssAuditor/resources/dummy.swf%22.xml&clutter=%3Cp%3E' because its source code was found within the request. The auditor was enabled as the server sent neither an 'X-XSS-Protection' nor 'Content-Security-Policy' header.
+Check that the XSSAuditor catches reflected tags in path components
+
+
Added: trunk/LayoutTests/http/tests/security/xssAuditor/embed-tag-in-path-unterminated.html (0 => 195073)
--- trunk/LayoutTests/http/tests/security/xssAuditor/embed-tag-in-path-unterminated.html (rev 0)
+++ trunk/LayoutTests/http/tests/security/xssAuditor/embed-tag-in-path-unterminated.html 2016-01-14 21:37:49 UTC (rev 195073)
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+if (window.testRunner) {
+ testRunner.dumpAsText();
+ testRunner.setXSSAuditorEnabled(true);
+}
+</script>
+</head>
+<body>
+<p>Check that the XSSAuditor catches reflected tags in path components</p>
+<iframe src="" height=%22500%22src=%22https://127.0.0.1:8443/security/xssAuditor/resources/dummy.swf%22.xml&clutter=<p>"></iframe>
+</body>
+</html>
Modified: trunk/LayoutTests/http/tests/security/xssAuditor/intercept/.htaccess (195072 => 195073)
--- trunk/LayoutTests/http/tests/security/xssAuditor/intercept/.htaccess 2016-01-14 21:31:05 UTC (rev 195072)
+++ trunk/LayoutTests/http/tests/security/xssAuditor/intercept/.htaccess 2016-01-14 21:37:49 UTC (rev 195073)
@@ -1,2 +1,5 @@
+# For ease in testing path reflections, pass any path component containing <'"
+# (and subsequent characters) as the "q" query parameter to the script identified
+# by the path components preceeding it.
RewriteEngine on
-RewriteRule ^(.*)/(.*) /security/xssAuditor/resources/$1?q=$2 [L,NS]
+RewriteRule ^([^<"']*)/(.*) /security/xssAuditor/resources/$1?q=$2 [L,NS]
Modified: trunk/Source/WebCore/ChangeLog (195072 => 195073)
--- trunk/Source/WebCore/ChangeLog 2016-01-14 21:31:05 UTC (rev 195072)
+++ trunk/Source/WebCore/ChangeLog 2016-01-14 21:37:49 UTC (rev 195073)
@@ -1,3 +1,23 @@
+2016-01-14 Daniel Bates <[email protected]>
+
+ [XSS Auditor] Partial bypass when web server collapses path components
+ https://bugs.webkit.org/show_bug.cgi?id=152872
+
+ Reviewed by Brent Fulgham.
+
+ Merged from Blink (patch by Tom Sepez <[email protected]>):
+ <https://src.chromium.org/viewvc/blink?revision=167610&view=revision>
+
+ Test: http/tests/security/xssAuditor/embed-tag-in-path-unterminated.html
+
+ * html/parser/XSSAuditor.cpp:
+ (WebCore::isNonCanonicalCharacter):
+ (WebCore::XSSAuditor::init):
+ (WebCore::XSSAuditor::decodedSnippetForName):
+ (WebCore::XSSAuditor::decodedSnippetForAttribute):
+ (WebCore::XSSAuditor::decodedSnippetForJavaScript):
+ (WebCore::fullyDecodeString): Deleted.
+
2016-01-14 Beth Dakin <[email protected]>
imported/blink/editing/text-iterator/read-past-cloned-first-letter.html
Modified: trunk/Source/WebCore/html/parser/XSSAuditor.cpp (195072 => 195073)
--- trunk/Source/WebCore/html/parser/XSSAuditor.cpp 2016-01-14 21:31:05 UTC (rev 195072)
+++ trunk/Source/WebCore/html/parser/XSSAuditor.cpp 2016-01-14 21:37:49 UTC (rev 195073)
@@ -56,9 +56,11 @@
// Note, we don't remove backslashes like PHP stripslashes(), which among other things converts "\\0" to the \0 character.
// Instead, we remove backslashes and zeros (since the string "\\0" =(remove backslashes)=> "0"). However, this has the
// adverse effect that we remove any legitimate zeros from a string.
+ // We also remove forward-slash, because it is common for some servers to collapse successive path components, eg,
+ // a//b becomes a/b.
//
- // For instance: new String("http://localhost:8000") => new String("http://localhost:8").
- return (c == '\\' || c == '0' || c == '\0' || c >= 127);
+ // For instance: new String("http://localhost:8000") => new String("http:localhost:8").
+ return (c == '\\' || c == '0' || c == '\0' || c == '/' || c >= 127);
}
static String canonicalize(const String& string)
@@ -175,7 +177,6 @@
workingString = decode16BitUnicodeEscapeSequences(decodeStandardURLEscapeSequences(workingString, encoding));
} while (workingString.length() < oldWorkingStringLength);
workingString.replace('+', ' ');
- workingString = canonicalize(workingString);
return workingString;
}
@@ -268,7 +269,7 @@
if (document->decoder())
m_encoding = document->decoder()->encoding();
- m_decodedURL = fullyDecodeString(m_documentURL.string(), m_encoding);
+ m_decodedURL = canonicalize(fullyDecodeString(m_documentURL.string(), m_encoding));
if (m_decodedURL.find(isRequiredForInjection) == notFound)
m_decodedURL = String();
@@ -306,7 +307,7 @@
if (httpBody && !httpBody->isEmpty()) {
httpBodyAsString = httpBody->flattenToString();
if (!httpBodyAsString.isEmpty()) {
- m_decodedHTTPBody = fullyDecodeString(httpBodyAsString, m_encoding);
+ m_decodedHTTPBody = canonicalize(fullyDecodeString(httpBodyAsString, m_encoding));
if (m_decodedHTTPBody.find(isRequiredForInjection) == notFound)
m_decodedHTTPBody = String();
if (m_decodedHTTPBody.length() >= minimumLengthForSuffixTree)
@@ -567,7 +568,7 @@
String XSSAuditor::decodedSnippetForName(const FilterTokenRequest& request)
{
// Grab a fixed number of characters equal to the length of the token's name plus one (to account for the "<").
- return fullyDecodeString(request.sourceTracker.source(request.token), m_encoding).substring(0, request.token.name().size() + 1);
+ return canonicalize(fullyDecodeString(request.sourceTracker.source(request.token), m_encoding).substring(0, request.token.name().size() + 1));
}
String XSSAuditor::decodedSnippetForAttribute(const FilterTokenRequest& request, const HTMLToken::Attribute& attribute, AttributeKind treatment)
@@ -578,6 +579,9 @@
// FIXME: We should grab one character before the name also.
unsigned start = attribute.startOffset;
unsigned end = attribute.endOffset;
+
+ // We defer canonicalizing the decoded string here to preserve embedded slashes (if any) that
+ // may lead us to truncate the string.
String decodedSnippet = fullyDecodeString(request.sourceTracker.source(request.token, start, end), m_encoding);
decodedSnippet.truncate(kMaximumFragmentLengthTarget);
if (treatment == SrcLikeAttribute) {
@@ -626,7 +630,7 @@
decodedSnippet.truncate(position);
}
}
- return decodedSnippet;
+ return canonicalize(decodedSnippet);
}
String XSSAuditor::decodedSnippetForJavaScript(const FilterTokenRequest& request)
@@ -697,7 +701,7 @@
lastNonSpacePosition = foundPosition;
}
- result = fullyDecodeString(string.substring(startPosition, foundPosition - startPosition), m_encoding);
+ result = canonicalize(fullyDecodeString(string.substring(startPosition, foundPosition - startPosition), m_encoding));
startPosition = foundPosition + 1;
}
return result;