OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2011 Adam Barth. All Rights Reserved. | 2 * Copyright (C) 2011 Adam Barth. All Rights Reserved. |
3 * Copyright (C) 2011 Daniel Bates (dbates@intudata.com). | 3 * Copyright (C) 2011 Daniel Bates (dbates@intudata.com). |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
7 * are met: | 7 * are met: |
8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
242 return FilterReflectedXSS; | 242 return FilterReflectedXSS; |
243 | 243 |
244 return result; | 244 return result; |
245 } | 245 } |
246 | 246 |
247 static bool isSemicolonSeparatedAttribute(const HTMLToken::Attribute& attribute) | 247 static bool isSemicolonSeparatedAttribute(const HTMLToken::Attribute& attribute) |
248 { | 248 { |
249 return threadSafeMatch(attribute.name, SVGNames::valuesAttr); | 249 return threadSafeMatch(attribute.name, SVGNames::valuesAttr); |
250 } | 250 } |
251 | 251 |
252 static bool semicolonSeparatedValueContainsJavaScriptURL(const String& value) | 252 static String semicolonSeparatedValueContainingJavaScriptURL(const String& value ) |
253 { | 253 { |
254 Vector<String> valueList; | 254 Vector<String> valueList; |
255 value.split(';', valueList); | 255 value.split(';', valueList); |
256 for (size_t i = 0; i < valueList.size(); ++i) { | 256 for (size_t i = 0; i < valueList.size(); ++i) { |
257 if (protocolIsJavaScript(valueList[i])) | 257 String stripped = stripLeadingAndTrailingHTMLSpaces(valueList[i]); |
258 return true; | 258 if (protocolIsJavaScript(stripped)) |
259 return stripped; | |
259 } | 260 } |
260 return false; | 261 return String(""); |
abarth-chromium
2014/06/17 21:54:07
return emptyString()
| |
261 } | 262 } |
262 | 263 |
263 XSSAuditor::XSSAuditor() | 264 XSSAuditor::XSSAuditor() |
264 : m_isEnabled(false) | 265 : m_isEnabled(false) |
265 , m_xssProtection(FilterReflectedXSS) | 266 , m_xssProtection(FilterReflectedXSS) |
266 , m_didSendValidCSPHeader(false) | 267 , m_didSendValidCSPHeader(false) |
267 , m_didSendValidXSSProtectionHeader(false) | 268 , m_didSendValidXSSProtectionHeader(false) |
268 , m_state(Uninitialized) | 269 , m_state(Uninitialized) |
269 , m_scriptTagFoundInRequest(false) | 270 , m_scriptTagFoundInRequest(false) |
270 , m_scriptTagNestingLevel(0) | 271 , m_scriptTagNestingLevel(0) |
(...skipping 322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
593 | 594 |
594 return eraseAttributeIfInjected(request, formactionAttr, kURLWithUniqueOrigi n, SrcLikeAttributeTruncation); | 595 return eraseAttributeIfInjected(request, formactionAttr, kURLWithUniqueOrigi n, SrcLikeAttributeTruncation); |
595 } | 596 } |
596 | 597 |
597 bool XSSAuditor::eraseDangerousAttributesIfInjected(const FilterTokenRequest& re quest) | 598 bool XSSAuditor::eraseDangerousAttributesIfInjected(const FilterTokenRequest& re quest) |
598 { | 599 { |
599 DEFINE_STATIC_LOCAL(String, safeJavaScriptURL, ("javascript:void(0)")); | 600 DEFINE_STATIC_LOCAL(String, safeJavaScriptURL, ("javascript:void(0)")); |
600 | 601 |
601 bool didBlockScript = false; | 602 bool didBlockScript = false; |
602 for (size_t i = 0; i < request.token.attributes().size(); ++i) { | 603 for (size_t i = 0; i < request.token.attributes().size(); ++i) { |
604 bool eraseAttribute = false; | |
605 bool valueContainsJavaScriptURL = false; | |
603 const HTMLToken::Attribute& attribute = request.token.attributes().at(i) ; | 606 const HTMLToken::Attribute& attribute = request.token.attributes().at(i) ; |
604 bool isInlineEventHandler = isNameOfInlineEventHandler(attribute.name); | 607 // FIXME: Don't create a new String for every attribute.value in the doc ument. |
605 // FIXME: It would be better if we didn't create a new String for every attribute in the document. | 608 if (isNameOfInlineEventHandler(attribute.name)) { |
606 String strippedValue = stripLeadingAndTrailingHTMLSpaces(String(attribut e.value)); | 609 eraseAttribute = isContainedInRequest(canonicalize(snippetFromAttrib ute(request, attribute), ScriptLikeAttributeTruncation)); |
607 bool valueContainsJavaScriptURL = (!isInlineEventHandler && protocolIsJa vaScript(strippedValue)) || (isSemicolonSeparatedAttribute(attribute) && semicol onSeparatedValueContainsJavaScriptURL(strippedValue)); | 610 } else if (protocolIsJavaScript(stripLeadingAndTrailingHTMLSpaces(String (attribute.value)))) { |
608 if (!isInlineEventHandler && !valueContainsJavaScriptURL) | 611 valueContainsJavaScriptURL = true; |
609 continue; | 612 eraseAttribute = isContainedInRequest(canonicalize(snippetFromAttrib ute(request, attribute), ScriptLikeAttributeTruncation)); |
610 if (!isContainedInRequest(canonicalize(snippetFromAttribute(request, att ribute), ScriptLikeAttributeTruncation))) | 613 } else if (isSemicolonSeparatedAttribute(attribute)) { |
614 String subValue = semicolonSeparatedValueContainingJavaScriptURL(Str ing(attribute.value)); | |
615 if (!subValue.isEmpty()) { | |
616 valueContainsJavaScriptURL = true; | |
617 eraseAttribute = isContainedInRequest(canonicalize(nameFromAttri bute(request, attribute), NoTruncation)) | |
618 && isContainedInRequest(canonicalize(subValue, ScriptLikeAtt ributeTruncation)); | |
619 } | |
620 } | |
621 if (!eraseAttribute) | |
611 continue; | 622 continue; |
612 request.token.eraseValueOfAttribute(i); | 623 request.token.eraseValueOfAttribute(i); |
613 if (valueContainsJavaScriptURL) | 624 if (valueContainsJavaScriptURL) |
614 request.token.appendToAttributeValue(i, safeJavaScriptURL); | 625 request.token.appendToAttributeValue(i, safeJavaScriptURL); |
615 didBlockScript = true; | 626 didBlockScript = true; |
616 } | 627 } |
617 return didBlockScript; | 628 return didBlockScript; |
618 } | 629 } |
619 | 630 |
620 bool XSSAuditor::eraseAttributeIfInjected(const FilterTokenRequest& request, con st QualifiedName& attributeName, const String& replacementValue, TruncationKind treatment) | 631 bool XSSAuditor::eraseAttributeIfInjected(const FilterTokenRequest& request, con st QualifiedName& attributeName, const String& replacementValue, TruncationKind treatment) |
(...skipping 20 matching lines...) Expand all Loading... | |
641 | 652 |
642 return true; | 653 return true; |
643 } | 654 } |
644 | 655 |
645 String XSSAuditor::canonicalizedSnippetForTagName(const FilterTokenRequest& requ est) | 656 String XSSAuditor::canonicalizedSnippetForTagName(const FilterTokenRequest& requ est) |
646 { | 657 { |
647 // Grab a fixed number of characters equal to the length of the token's name plus one (to account for the "<"). | 658 // Grab a fixed number of characters equal to the length of the token's name plus one (to account for the "<"). |
648 return canonicalize(request.sourceTracker.sourceForToken(request.token).subs tring(0, request.token.name().size() + 1), NoTruncation); | 659 return canonicalize(request.sourceTracker.sourceForToken(request.token).subs tring(0, request.token.name().size() + 1), NoTruncation); |
649 } | 660 } |
650 | 661 |
662 String XSSAuditor::nameFromAttribute(const FilterTokenRequest& request, const HT MLToken::Attribute& attribute) | |
663 { | |
664 // The range inlcudes the character which terminates the name. So, | |
665 // for an input of |name="value"|, the snippet is |name=|. | |
666 int start = attribute.nameRange.start - request.token.startIndex(); | |
667 int end = attribute.valueRange.start - request.token.startIndex(); | |
668 return request.sourceTracker.sourceForToken(request.token).substring(start, end - start); | |
669 } | |
670 | |
651 String XSSAuditor::snippetFromAttribute(const FilterTokenRequest& request, const HTMLToken::Attribute& attribute) | 671 String XSSAuditor::snippetFromAttribute(const FilterTokenRequest& request, const HTMLToken::Attribute& attribute) |
652 { | 672 { |
653 // The range doesn't inlcude the character which terminates the value. So, | 673 // The range doesn't include the character which terminates the value. So, |
654 // for an input of |name="value"|, the snippet is |name="value|. For an | 674 // for an input of |name="value"|, the snippet is |name="value|. For an |
655 // unquoted input of |name=value |, the snippet is |name=value|. | 675 // unquoted input of |name=value |, the snippet is |name=value|. |
656 // FIXME: We should grab one character before the name also. | 676 // FIXME: We should grab one character before the name also. |
657 int start = attribute.nameRange.start - request.token.startIndex(); | 677 int start = attribute.nameRange.start - request.token.startIndex(); |
658 int end = attribute.valueRange.end - request.token.startIndex(); | 678 int end = attribute.valueRange.end - request.token.startIndex(); |
659 return request.sourceTracker.sourceForToken(request.token).substring(start, end - start); | 679 return request.sourceTracker.sourceForToken(request.token).substring(start, end - start); |
660 } | 680 } |
661 | 681 |
662 String XSSAuditor::canonicalize(String snippet, TruncationKind treatment) | 682 String XSSAuditor::canonicalize(String snippet, TruncationKind treatment) |
663 { | 683 { |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
780 | 800 |
781 bool XSSAuditor::isSafeToSendToAnotherThread() const | 801 bool XSSAuditor::isSafeToSendToAnotherThread() const |
782 { | 802 { |
783 return m_documentURL.isSafeToSendToAnotherThread() | 803 return m_documentURL.isSafeToSendToAnotherThread() |
784 && m_decodedURL.isSafeToSendToAnotherThread() | 804 && m_decodedURL.isSafeToSendToAnotherThread() |
785 && m_decodedHTTPBody.isSafeToSendToAnotherThread() | 805 && m_decodedHTTPBody.isSafeToSendToAnotherThread() |
786 && m_httpBodyAsString.isSafeToSendToAnotherThread(); | 806 && m_httpBodyAsString.isSafeToSendToAnotherThread(); |
787 } | 807 } |
788 | 808 |
789 } // namespace WebCore | 809 } // namespace WebCore |
OLD | NEW |