Changeset 49644 in webkit
- Timestamp:
- Oct 15, 2009 12:04:57 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 18 added
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r49640 r49644 1 2009-10-15 Daniel Bates <dbates@webkit.org> 2 3 Reviewed by Adam Barth. 4 5 https://bugs.webkit.org/show_bug.cgi?id=27895 6 7 Tests that inline event handlers whose value ends in a single-line JavaScript 8 comment cannot bypass the XSSAuditor. Also tests that the XSSAuditor prevents 9 similar attack vectors with respect to the HTML Base element, HTML Object 10 element, and external JavaScripts. 11 12 * http/tests/security/xssAuditor/base-href-comment-expected.txt: Added. 13 * http/tests/security/xssAuditor/base-href-comment.html: Added. 14 * http/tests/security/xssAuditor/iframe-javascript-url-comment-expected.txt: Added. 15 * http/tests/security/xssAuditor/iframe-javascript-url-comment.html: Added. 16 * http/tests/security/xssAuditor/img-onerror-HTML-comment-expected.txt: Added. 17 * http/tests/security/xssAuditor/img-onerror-HTML-comment.html: Added. 18 * http/tests/security/xssAuditor/img-onerror-comment-expected.txt: Added. 19 * http/tests/security/xssAuditor/img-onerror-comment.html: Added. 20 * http/tests/security/xssAuditor/object-tag-comment-expected.txt: Added. 21 * http/tests/security/xssAuditor/object-tag-comment.html: Added. 22 * http/tests/security/xssAuditor/resources/echo-before-image.pl: Added. 23 * http/tests/security/xssAuditor/resources/echo-head-base-href-comment.pl: Added. 24 * http/tests/security/xssAuditor/script-tag-comment-HTML-entity-expected.txt: Added. 25 * http/tests/security/xssAuditor/script-tag-comment-HTML-entity.html: Added. 26 * http/tests/security/xssAuditor/script-tag-comment-expected.txt: Added. 27 * http/tests/security/xssAuditor/script-tag-comment.html: Added. 28 * http/tests/security/xssAuditor/script-tag-with-source-comment-expected.txt: Added. 29 * http/tests/security/xssAuditor/script-tag-with-source-comment.html: Added. 30 1 31 2009-10-15 Brian Weinstein <bweinstein@apple.com> 2 32 -
trunk/WebCore/ChangeLog
r49641 r49644 1 2009-10-15 Daniel Bates <dbates@webkit.org> 2 3 Reviewed by Adam Barth. 4 5 https://bugs.webkit.org/show_bug.cgi?id=27895 6 7 Fixes an issue in which injecting an inline event handler whose value ends in a single-line 8 JavaScript comment can bypass the XSSAuditor. Similarly fixes this issue with respect to 9 the HTML Base element, HTML Object element, inline and external script tags, and 10 JavaScript multi-line variants of all of these attacks. 11 12 Tests: http/tests/security/xssAuditor/base-href-comment.html 13 http/tests/security/xssAuditor/iframe-javascript-url-comment.html 14 http/tests/security/xssAuditor/img-onerror-HTML-comment.html 15 http/tests/security/xssAuditor/img-onerror-comment.html 16 http/tests/security/xssAuditor/object-tag-comment.html 17 http/tests/security/xssAuditor/script-tag-comment-HTML-entity.html 18 http/tests/security/xssAuditor/script-tag-comment.html 19 http/tests/security/xssAuditor/script-tag-with-source-comment.html 20 21 * page/XSSAuditor.cpp: Added constant minAttackLength. 22 (WebCore::XSSAuditor::canEvaluate): 23 (WebCore::XSSAuditor::canEvaluateJavaScriptURL): 24 (WebCore::XSSAuditor::canCreateInlineEventListener): 25 (WebCore::XSSAuditor::canLoadExternalScriptFromSrc): 26 (WebCore::XSSAuditor::canLoadObject): 27 (WebCore::XSSAuditor::canSetBaseElementURL): 28 (WebCore::XSSAuditor::findInRequest): Added parameter context. Only looks at up 29 to minAttackLength of script code plus context (if any). 30 * page/XSSAuditor.h: 31 1 32 2009-10-08 Adam Langley <agl@google.com> 2 33 -
trunk/WebCore/page/XSSAuditor.cpp
r49605 r49644 47 47 namespace WebCore { 48 48 49 // Note, we believe it is sufficient to only look at a substring of 7 50 // characters (or less) of code. Observe that "alert()" is seven characters 51 // in length. 52 static const unsigned minAttackLength = 7; 53 49 54 static bool isNonCanonicalCharacter(UChar c) 50 55 { … … 106 111 return true; 107 112 108 if (findInRequest( code, false, true)) {113 if (findInRequest(String(), code, false, true)) { 109 114 DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request.\n")); 110 115 m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String()); … … 119 124 return true; 120 125 121 if (findInRequest( code, true, false, true)) {126 if (findInRequest(String(), code, true, false, true)) { 122 127 DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request.\n")); 123 128 m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String()); … … 132 137 return true; 133 138 134 if (findInRequest( code, true, true)) {139 if (findInRequest(String(), code, true, true)) { 135 140 DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request.\n")); 136 141 m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String()); … … 155 160 return true; 156 161 157 if (findInRequest(context +url)) {162 if (findInRequest(context, url)) { 158 163 DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request.\n")); 159 164 m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String()); … … 168 173 return true; 169 174 170 if (findInRequest( url)) {175 if (findInRequest(String(), url)) { 171 176 DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request")); 172 177 m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String()); … … 182 187 183 188 KURL baseElementURL(m_frame->document()->url(), url); 184 if (m_frame->document()->url().host() != baseElementURL.host() && findInRequest( url)) {189 if (m_frame->document()->url().host() != baseElementURL.host() && findInRequest(String(), url)) { 185 190 DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request")); 186 191 m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String()); … … 256 261 } 257 262 258 bool XSSAuditor::findInRequest(const String& string, bool decodeEntities, bool allowRequestIfNoIllegalURICharacters,263 bool XSSAuditor::findInRequest(const String& context, const String& string, bool decodeEntities, bool allowRequestIfNoIllegalURICharacters, 259 264 bool decodeURLEscapeSequencesTwice) const 260 265 { … … 262 267 Frame* parentFrame = m_frame->tree()->parent(); 263 268 if (parentFrame && m_frame->document()->url() == blankURL()) 264 result = findInRequest(parentFrame, string, decodeEntities, allowRequestIfNoIllegalURICharacters, decodeURLEscapeSequencesTwice);269 result = findInRequest(parentFrame, context, string, decodeEntities, allowRequestIfNoIllegalURICharacters, decodeURLEscapeSequencesTwice); 265 270 if (!result) 266 result = findInRequest(m_frame, string, decodeEntities, allowRequestIfNoIllegalURICharacters, decodeURLEscapeSequencesTwice);271 result = findInRequest(m_frame, context, string, decodeEntities, allowRequestIfNoIllegalURICharacters, decodeURLEscapeSequencesTwice); 267 272 return result; 268 273 } 269 274 270 bool XSSAuditor::findInRequest(Frame* frame, const String& string, bool decodeEntities, bool allowRequestIfNoIllegalURICharacters,275 bool XSSAuditor::findInRequest(Frame* frame, const String& context, const String& string, bool decodeEntities, bool allowRequestIfNoIllegalURICharacters, 271 276 bool decodeURLEscapeSequencesTwice) const 272 277 { … … 282 287 283 288 FormData* formDataObj = frame->loader()->documentLoader()->originalRequest().httpBody(); 289 const bool hasFormData = formDataObj && !formDataObj->isEmpty(); 284 290 String pageURL = frame->document()->url().string(); 285 286 if (!formDataObj && string.length() >= 2 * pageURL.length()) { 291 292 String canonicalizedString; 293 if (!hasFormData && string.length() > 2 * pageURL.length()) { 287 294 // Q: Why do we bother to do this check at all? 288 295 // A: Canonicalizing large inline scripts can be expensive. We want to 289 // bail out before the call to canonicalize below, which could290 // result in an unneeded allocation and memcpy.296 // reduce the size of the string before we call canonicalize below, 297 // since it could result in an unneeded allocation and memcpy. 291 298 // 292 299 // Q: Why do we multiply by two here? … … 296 303 // factor of two by sending " characters, which the server 297 304 // transforms to \". 298 return false; 299 } 305 canonicalizedString = string.substring(0, 2 * pageURL.length()); 306 } else 307 canonicalizedString = string; 300 308 301 309 if (frame->document()->url().protocolIs("data")) 302 310 return false; 303 311 304 String canonicalizedString = canonicalize(string);312 canonicalizedString = canonicalize(canonicalizedString); 305 313 if (canonicalizedString.isEmpty()) 306 314 return false; 307 315 308 if (string.length() < pageURL.length()) { 309 // The string can actually fit inside the pageURL. 310 String decodedPageURL = m_cache.canonicalizeURL(pageURL, frame->document()->decoder()->encoding(), decodeEntities, decodeURLEscapeSequencesTwice); 311 312 if (allowRequestIfNoIllegalURICharacters && (!formDataObj || formDataObj->isEmpty()) 313 && decodedPageURL.find(&isIllegalURICharacter, 0) == -1) 314 return false; // Injection is impossible because the request does not contain any illegal URI characters. 315 316 if (decodedPageURL.find(canonicalizedString, 0, false) != -1) 317 return true; // We've found the smoking gun. 318 } 319 320 if (formDataObj && !formDataObj->isEmpty()) { 321 String formData = formDataObj->flattenToString(); 322 if (string.length() < formData.length()) { 323 // Notice it is sufficient to compare the length of the string to 324 // the url-encoded POST data because the length of the url-decoded 325 // code is less than or equal to the length of the url-encoded 326 // string. 327 String decodedFormData = m_cache.canonicalizeURL(formData, frame->document()->decoder()->encoding(), decodeEntities, decodeURLEscapeSequencesTwice); 328 if (decodedFormData.find(canonicalizedString, 0, false) != -1) 329 return true; // We found the string in the POST data. 330 } 316 // We only look at the first minAttackLength characters to avoid looking at 317 // characters the attacker has pulled in from the page using an attack string 318 // like: <img onerror="alert(/XSS/);// 319 canonicalizedString = canonicalizedString.substring(0, minAttackLength); 320 321 if (!context.isEmpty()) 322 canonicalizedString = context + canonicalizedString; 323 324 String decodedPageURL = m_cache.canonicalizeURL(pageURL, frame->document()->decoder()->encoding(), decodeEntities, decodeURLEscapeSequencesTwice); 325 326 if (allowRequestIfNoIllegalURICharacters && !hasFormData && decodedPageURL.find(&isIllegalURICharacter, 0) == -1) 327 return false; // Injection is impossible because the request does not contain any illegal URI characters. 328 329 if (decodedPageURL.find(canonicalizedString, 0, false) != -1) 330 return true; // We've found the string in the GET data. 331 332 if (hasFormData) { 333 String decodedFormData = m_cache.canonicalizeURL(formDataObj->flattenToString(), frame->document()->decoder()->encoding(), decodeEntities, decodeURLEscapeSequencesTwice); 334 if (decodedFormData.find(canonicalizedString, 0, false) != -1) 335 return true; // We found the string in the POST data. 331 336 } 332 337 -
trunk/WebCore/page/XSSAuditor.h
r49434 r49644 123 123 static String decodeHTMLEntities(const String&, bool leaveUndecodableEntitiesUntouched = true); 124 124 125 bool findInRequest(const String& , bool decodeEntities = true, bool allowRequestIfNoIllegalURICharacters = false,125 bool findInRequest(const String& context, const String&, bool decodeEntities = true, bool allowRequestIfNoIllegalURICharacters = false, 126 126 bool decodeURLEscapeSequencesTwice = false) const; 127 bool findInRequest(Frame*, const String& , bool decodeEntities = true, bool allowRequestIfNoIllegalURICharacters = false,127 bool findInRequest(Frame*, const String& context, const String&, bool decodeEntities = true, bool allowRequestIfNoIllegalURICharacters = false, 128 128 bool decodeURLEscapeSequencesTwice = false) const; 129 129
Note: See TracChangeset
for help on using the changeset viewer.