Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(90)

Unified Diff: Source/WebCore/html/parser/XSSAuditor.cpp

Issue 9701035: Merge 108881 - XSS Auditor targeting legitimate frames as false positives. (Closed) Base URL: http://svn.webkit.org/repository/webkit/branches/chromium/1025/
Patch Set: Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/WebCore/html/parser/XSSAuditor.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/WebCore/html/parser/XSSAuditor.cpp
===================================================================
--- Source/WebCore/html/parser/XSSAuditor.cpp (revision 110728)
+++ Source/WebCore/html/parser/XSSAuditor.cpp (working copy)
@@ -277,7 +277,7 @@
case AfterScriptStartTag:
didBlockScript = filterTokenAfterScriptStartTag(token);
ASSERT(m_state == Initial);
- m_cachedSnippet = String();
+ m_cachedDecodedSnippet = String();
break;
}
@@ -341,16 +341,10 @@
return false;
}
- TextResourceDecoder* decoder = m_parser->document()->decoder();
- if (isContainedInRequest(fullyDecodeString(m_cachedSnippet, decoder))) {
- int start = 0;
- int end = token.endIndex() - token.startIndex();
- String snippet = snippetForJavaScript(snippetForRange(token, start, end));
- if (isContainedInRequest(fullyDecodeString(snippet, decoder))) {
- token.eraseCharacters();
- token.appendToCharacter(' '); // Technically, character tokens can't be empty.
- return true;
- }
+ if (isContainedInRequest(m_cachedDecodedSnippet) && isContainedInRequest(decodedSnippetForJavaScript(token))) {
+ token.eraseCharacters();
+ token.appendToCharacter(' '); // Technically, character tokens can't be empty.
+ return true;
}
return false;
}
@@ -361,11 +355,12 @@
ASSERT(token.type() == HTMLTokenTypes::StartTag);
ASSERT(hasName(token, scriptTag));
- if (eraseAttributeIfInjected(token, srcAttr, blankURL().string(), SrcLikeAttribute))
- return true;
+ m_state = AfterScriptStartTag;
+ m_cachedDecodedSnippet = stripLeadingAndTrailingHTMLSpaces(decodedSnippetForToken(token));
- m_state = AfterScriptStartTag;
- m_cachedSnippet = m_parser->sourceForToken(token);
+ if (isContainedInRequest(decodedSnippetForName(token)))
+ return eraseAttributeIfInjected(token, srcAttr, blankURL().string(), SrcLikeAttribute);
+
return false;
}
@@ -376,11 +371,11 @@
ASSERT(hasName(token, objectTag));
bool didBlockScript = false;
-
- didBlockScript |= eraseAttributeIfInjected(token, dataAttr, blankURL().string(), SrcLikeAttribute);
- didBlockScript |= eraseAttributeIfInjected(token, typeAttr);
- didBlockScript |= eraseAttributeIfInjected(token, classidAttr);
-
+ if (isContainedInRequest(decodedSnippetForName(token))) {
+ didBlockScript |= eraseAttributeIfInjected(token, dataAttr, blankURL().string(), SrcLikeAttribute);
+ didBlockScript |= eraseAttributeIfInjected(token, typeAttr);
+ didBlockScript |= eraseAttributeIfInjected(token, classidAttr);
+ }
return didBlockScript;
}
@@ -410,11 +405,11 @@
ASSERT(hasName(token, embedTag));
bool didBlockScript = false;
-
- didBlockScript |= eraseAttributeIfInjected(token, codeAttr, String(), SrcLikeAttribute);
- didBlockScript |= eraseAttributeIfInjected(token, srcAttr, blankURL().string(), SrcLikeAttribute);
- didBlockScript |= eraseAttributeIfInjected(token, typeAttr);
-
+ if (isContainedInRequest(decodedSnippetForName(token))) {
+ didBlockScript |= eraseAttributeIfInjected(token, codeAttr, String(), SrcLikeAttribute);
+ didBlockScript |= eraseAttributeIfInjected(token, srcAttr, blankURL().string(), SrcLikeAttribute);
+ didBlockScript |= eraseAttributeIfInjected(token, typeAttr);
+ }
return didBlockScript;
}
@@ -425,10 +420,10 @@
ASSERT(hasName(token, appletTag));
bool didBlockScript = false;
-
- didBlockScript |= eraseAttributeIfInjected(token, codeAttr, String(), SrcLikeAttribute);
- didBlockScript |= eraseAttributeIfInjected(token, objectAttr);
-
+ if (isContainedInRequest(decodedSnippetForName(token))) {
+ didBlockScript |= eraseAttributeIfInjected(token, codeAttr, String(), SrcLikeAttribute);
+ didBlockScript |= eraseAttributeIfInjected(token, objectAttr);
+ }
return didBlockScript;
}
@@ -438,7 +433,10 @@
ASSERT(token.type() == HTMLTokenTypes::StartTag);
ASSERT(hasName(token, iframeTag));
- return eraseAttributeIfInjected(token, srcAttr, String(), SrcLikeAttribute);
+ if (isContainedInRequest(decodedSnippetForName(token)))
+ return eraseAttributeIfInjected(token, srcAttr, String(), SrcLikeAttribute);
+
+ return false;
}
bool XSSAuditor::filterMetaToken(HTMLToken& token)
@@ -531,13 +529,19 @@
return false;
}
-String XSSAuditor::snippetForRange(const HTMLToken& token, int start, int end)
+String XSSAuditor::decodedSnippetForToken(const HTMLToken& token)
{
- // FIXME: There's an extra allocation here that we could save by
- // passing the range to the parser.
- return m_parser->sourceForToken(token).substring(start, end - start);
+ String snippet = m_parser->sourceForToken(token);
+ return fullyDecodeString(snippet, m_parser->document()->decoder());
}
+String XSSAuditor::decodedSnippetForName(const HTMLToken& token)
+{
+ // Grab a fixed number of characters equal to the length of the token's
+ // name plus one (to account for the "<").
+ return decodedSnippetForToken(token).substring(0, token.name().size() + 1);
+}
+
String XSSAuditor::decodedSnippetForAttribute(const HTMLToken& token, const HTMLToken::Attribute& attribute, AttributeKind treatment)
{
const size_t kMaximumSnippetLength = 100;
@@ -548,7 +552,7 @@
// FIXME: We should grab one character before the name also.
int start = attribute.m_nameRange.m_start - token.startIndex();
int end = attribute.m_valueRange.m_end - token.startIndex();
- String decodedSnippet = fullyDecodeString(snippetForRange(token, start, end), m_parser->document()->decoder());
+ String decodedSnippet = fullyDecodeString(m_parser->sourceForToken(token).substring(start, end - start), m_parser->document()->decoder());
decodedSnippet.truncate(kMaximumSnippetLength);
if (treatment == SrcLikeAttribute) {
int slashCount;
@@ -567,31 +571,9 @@
return decodedSnippet;
}
-bool XSSAuditor::isContainedInRequest(const String& decodedSnippet)
+String XSSAuditor::decodedSnippetForJavaScript(const HTMLToken& token)
{
- if (decodedSnippet.isEmpty())
- return false;
- if (m_decodedURL.find(decodedSnippet, 0, false) != notFound)
- return true;
- if (m_decodedHTTPBodySuffixTree && !m_decodedHTTPBodySuffixTree->mightContain(decodedSnippet))
- return false;
- return m_decodedHTTPBody.find(decodedSnippet, 0, false) != notFound;
-}
-
-bool XSSAuditor::isSameOriginResource(const String& url)
-{
- // If the resource is loaded from the same URL as the enclosing page, it's
- // probably not an XSS attack, so we reduce false positives by allowing the
- // request. If the resource has a query string, we're more suspicious,
- // however, because that's pretty rare and the attacker might be able to
- // trick a server-side script into doing something dangerous with the query
- // string.
- KURL resourceURL(m_parser->document()->url(), url);
- return (m_parser->document()->url().host() == resourceURL.host() && resourceURL.query().isEmpty());
-}
-
-String XSSAuditor::snippetForJavaScript(const String& string)
-{
+ String string = m_parser->sourceForToken(token);
const size_t kMaximumFragmentLengthTarget = 100;
size_t startPosition = 0;
@@ -637,7 +619,30 @@
}
}
- return string.substring(startPosition, endPosition - startPosition);
+ return fullyDecodeString(string.substring(startPosition, endPosition - startPosition), m_parser->document()->decoder());
}
+bool XSSAuditor::isContainedInRequest(const String& decodedSnippet)
+{
+ if (decodedSnippet.isEmpty())
+ return false;
+ if (m_decodedURL.find(decodedSnippet, 0, false) != notFound)
+ return true;
+ if (m_decodedHTTPBodySuffixTree && !m_decodedHTTPBodySuffixTree->mightContain(decodedSnippet))
+ return false;
+ return m_decodedHTTPBody.find(decodedSnippet, 0, false) != notFound;
+}
+
+bool XSSAuditor::isSameOriginResource(const String& url)
+{
+ // If the resource is loaded from the same URL as the enclosing page, it's
+ // probably not an XSS attack, so we reduce false positives by allowing the
+ // request. If the resource has a query string, we're more suspicious,
+ // however, because that's pretty rare and the attacker might be able to
+ // trick a server-side script into doing something dangerous with the query
+ // string.
+ KURL resourceURL(m_parser->document()->url(), url);
+ return (m_parser->document()->url().host() == resourceURL.host() && resourceURL.query().isEmpty());
+}
+
} // namespace WebCore
« no previous file with comments | « Source/WebCore/html/parser/XSSAuditor.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698