diff options
Diffstat (limited to 'WebCore/page/XSSAuditor.cpp')
-rw-r--r-- | WebCore/page/XSSAuditor.cpp | 96 |
1 files changed, 57 insertions, 39 deletions
diff --git a/WebCore/page/XSSAuditor.cpp b/WebCore/page/XSSAuditor.cpp index 72c2591..0129b52 100644 --- a/WebCore/page/XSSAuditor.cpp +++ b/WebCore/page/XSSAuditor.cpp @@ -105,7 +105,12 @@ bool XSSAuditor::canEvaluate(const String& code) const if (!isEnabled()) return true; - if (findInRequest(code, false, true)) { + FindTask task; + task.string = code; + task.decodeEntities = false; + task.allowRequestIfNoIllegalURICharacters = true; + + if (findInRequest(task)) { DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request.\n")); m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String()); return false; @@ -118,7 +123,11 @@ bool XSSAuditor::canEvaluateJavaScriptURL(const String& code) const if (!isEnabled()) return true; - if (findInRequest(code, true, false, true)) { + FindTask task; + task.string = code; + task.decodeURLEscapeSequencesTwice = true; + + if (findInRequest(task)) { DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request.\n")); m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String()); return false; @@ -131,7 +140,11 @@ bool XSSAuditor::canCreateInlineEventListener(const String&, const String& code) if (!isEnabled()) return true; - if (findInRequest(code, true, true)) { + FindTask task; + task.string = code; + task.allowRequestIfNoIllegalURICharacters = true; + + if (findInRequest(task)) { DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request.\n")); m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String()); return false; @@ -147,7 +160,11 @@ bool XSSAuditor::canLoadExternalScriptFromSrc(const String& context, const Strin if (isSameOriginResource(url)) return true; - if (findInRequest(context + url)) { + FindTask task; + task.context = context; + task.string = url; + + if (findInRequest(task)) { DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request.\n")); m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String()); return false; @@ -163,7 +180,11 @@ bool XSSAuditor::canLoadObject(const String& url) const if (isSameOriginResource(url)) return true; - if (findInRequest(url)) { + FindTask task; + task.string = url; + task.allowRequestIfNoIllegalURICharacters = true; + + if (findInRequest(task)) { String consoleMessage = String::format("Refused to load an object. URL found within request: \"%s\".\n", url.utf8().data()); m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String()); return false; @@ -179,7 +200,11 @@ bool XSSAuditor::canSetBaseElementURL(const String& url) const if (isSameOriginResource(url)) return true; - if (findInRequest(url)) { + FindTask task; + task.string = url; + task.allowRequestIfNoIllegalURICharacters = true; + + if (findInRequest(task)) { DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to load from document base URL. URL found within request.\n")); m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String()); return false; @@ -265,20 +290,18 @@ bool XSSAuditor::isSameOriginResource(const String& url) const return (m_frame->document()->url().host() == resourceURL.host() && resourceURL.query().isEmpty()); } -bool XSSAuditor::findInRequest(const String& string, bool decodeEntities, bool allowRequestIfNoIllegalURICharacters, - bool decodeURLEscapeSequencesTwice) const +bool XSSAuditor::findInRequest(const FindTask& task) const { bool result = false; Frame* parentFrame = m_frame->tree()->parent(); if (parentFrame && m_frame->document()->url() == blankURL()) - result = findInRequest(parentFrame, string, decodeEntities, allowRequestIfNoIllegalURICharacters, decodeURLEscapeSequencesTwice); + result = findInRequest(parentFrame, task); if (!result) - result = findInRequest(m_frame, string, decodeEntities, allowRequestIfNoIllegalURICharacters, decodeURLEscapeSequencesTwice); + result = findInRequest(m_frame, task); return result; } -bool XSSAuditor::findInRequest(Frame* frame, const String& string, bool decodeEntities, bool allowRequestIfNoIllegalURICharacters, - bool decodeURLEscapeSequencesTwice) const +bool XSSAuditor::findInRequest(Frame* frame, const FindTask& task) const { ASSERT(frame->document()); @@ -287,17 +310,19 @@ bool XSSAuditor::findInRequest(Frame* frame, const String& string, bool decodeEn return false; } - if (string.isEmpty()) + if (task.string.isEmpty()) return false; FormData* formDataObj = frame->loader()->documentLoader()->originalRequest().httpBody(); + const bool hasFormData = formDataObj && !formDataObj->isEmpty(); String pageURL = frame->document()->url().string(); - if (!formDataObj && string.length() >= 2 * pageURL.length()) { + String canonicalizedString; + if (!hasFormData && task.string.length() > 2 * pageURL.length()) { // Q: Why do we bother to do this check at all? // A: Canonicalizing large inline scripts can be expensive. We want to - // bail out before the call to canonicalize below, which could - // result in an unneeded allocation and memcpy. + // reduce the size of the string before we call canonicalize below, + // since it could result in an unneeded allocation and memcpy. // // Q: Why do we multiply by two here? // A: We attempt to detect reflected XSS even when the server @@ -305,39 +330,32 @@ bool XSSAuditor::findInRequest(Frame* frame, const String& string, bool decodeEn // attacker can do get the server to inflate his/her input by a // factor of two by sending " characters, which the server // transforms to \". - return false; - } + canonicalizedString = task.string.substring(0, 2 * pageURL.length()); + } else + canonicalizedString = task.string; if (frame->document()->url().protocolIs("data")) return false; - String canonicalizedString = canonicalize(string); + canonicalizedString = canonicalize(canonicalizedString); if (canonicalizedString.isEmpty()) return false; - if (string.length() < pageURL.length()) { - // The string can actually fit inside the pageURL. - String decodedPageURL = m_cache.canonicalizeURL(pageURL, frame->document()->decoder()->encoding(), decodeEntities, decodeURLEscapeSequencesTwice); + if (!task.context.isEmpty()) + canonicalizedString = task.context + canonicalizedString; - if (allowRequestIfNoIllegalURICharacters && (!formDataObj || formDataObj->isEmpty()) - && decodedPageURL.find(&isIllegalURICharacter, 0) == -1) - return false; // Injection is impossible because the request does not contain any illegal URI characters. + String decodedPageURL = m_cache.canonicalizeURL(pageURL, frame->document()->decoder()->encoding(), task.decodeEntities, task.decodeURLEscapeSequencesTwice); - if (decodedPageURL.find(canonicalizedString, 0, false) != -1) - return true; // We've found the smoking gun. - } + if (task.allowRequestIfNoIllegalURICharacters && !hasFormData && decodedPageURL.find(&isIllegalURICharacter, 0) == -1) + return false; // Injection is impossible because the request does not contain any illegal URI characters. - if (formDataObj && !formDataObj->isEmpty()) { - String formData = formDataObj->flattenToString(); - if (string.length() < formData.length()) { - // Notice it is sufficient to compare the length of the string to - // the url-encoded POST data because the length of the url-decoded - // code is less than or equal to the length of the url-encoded - // string. - String decodedFormData = m_cache.canonicalizeURL(formData, frame->document()->decoder()->encoding(), decodeEntities, decodeURLEscapeSequencesTwice); - if (decodedFormData.find(canonicalizedString, 0, false) != -1) - return true; // We found the string in the POST data. - } + if (decodedPageURL.find(canonicalizedString, 0, false) != -1) + return true; // We've found the string in the GET data. + + if (hasFormData) { + String decodedFormData = m_cache.canonicalizeURL(formDataObj->flattenToString(), frame->document()->decoder()->encoding(), task.decodeEntities, task.decodeURLEscapeSequencesTwice); + if (decodedFormData.find(canonicalizedString, 0, false) != -1) + return true; // We found the string in the POST data. } return false; |