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

Side by Side Diff: Source/core/html/parser/XSSAuditor.cpp

Issue 205243002: XSSAuditor bypass with script tag and expression following injection point (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Incorporate dbates's suggestions. Created 6 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « LayoutTests/http/tests/security/xssAuditor/script-tag-near-start-expected.txt ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 25 matching lines...) Expand all
36 #include "core/html/HTMLParamElement.h" 36 #include "core/html/HTMLParamElement.h"
37 #include "core/html/parser/HTMLDocumentParser.h" 37 #include "core/html/parser/HTMLDocumentParser.h"
38 #include "core/html/parser/HTMLParserIdioms.h" 38 #include "core/html/parser/HTMLParserIdioms.h"
39 #include "core/html/parser/TextResourceDecoder.h" 39 #include "core/html/parser/TextResourceDecoder.h"
40 #include "core/html/parser/XSSAuditorDelegate.h" 40 #include "core/html/parser/XSSAuditorDelegate.h"
41 #include "core/loader/DocumentLoader.h" 41 #include "core/loader/DocumentLoader.h"
42 #include "core/frame/Settings.h" 42 #include "core/frame/Settings.h"
43 #include "platform/JSONValues.h" 43 #include "platform/JSONValues.h"
44 #include "platform/network/FormData.h" 44 #include "platform/network/FormData.h"
45 #include "platform/text/DecodeEscapeSequences.h" 45 #include "platform/text/DecodeEscapeSequences.h"
46 #include "wtf/ASCIICType.h"
46 #include "wtf/MainThread.h" 47 #include "wtf/MainThread.h"
47 48
48 namespace { 49 namespace {
49 50
50 // SecurityOrigin::urlWithUniqueSecurityOrigin() can't be used cross-thread, or we'd use it instead. 51 // SecurityOrigin::urlWithUniqueSecurityOrigin() can't be used cross-thread, or we'd use it instead.
51 const char kURLWithUniqueOrigin[] = "data:,"; 52 const char kURLWithUniqueOrigin[] = "data:,";
52 53
53 } // namespace 54 } // namespace
54 55
55 namespace WebCore { 56 namespace WebCore {
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 } 92 }
92 93
93 static bool isJSNewline(UChar c) 94 static bool isJSNewline(UChar c)
94 { 95 {
95 // Per ecma-262 section 7.3 Line Terminators. 96 // Per ecma-262 section 7.3 Line Terminators.
96 return (c == '\n' || c == '\r' || c == 0x2028 || c == 0x2029); 97 return (c == '\n' || c == '\r' || c == 0x2028 || c == 0x2029);
97 } 98 }
98 99
99 static bool startsHTMLCommentAt(const String& string, size_t start) 100 static bool startsHTMLCommentAt(const String& string, size_t start)
100 { 101 {
101 return (start + 3 < string.length() && string[start] == '<' && string[start+ 1] == '!' && string[start+2] == '-' && string[start+3] == '-'); 102 return (start + 3 < string.length() && string[start] == '<' && string[start + 1] == '!' && string[start + 2] == '-' && string[start + 3] == '-');
102 } 103 }
103 104
104 static bool startsSingleLineCommentAt(const String& string, size_t start) 105 static bool startsSingleLineCommentAt(const String& string, size_t start)
105 { 106 {
106 return (start + 1 < string.length() && string[start] == '/' && string[start+ 1] == '/'); 107 return (start + 1 < string.length() && string[start] == '/' && string[start + 1] == '/');
107 } 108 }
108 109
109 static bool startsMultiLineCommentAt(const String& string, size_t start) 110 static bool startsMultiLineCommentAt(const String& string, size_t start)
110 { 111 {
111 return (start + 1 < string.length() && string[start] == '/' && string[start+ 1] == '*'); 112 return (start + 1 < string.length() && string[start] == '/' && string[start + 1] == '*');
113 }
114
115 static bool startsOpeningScriptTagAt(const String& string, size_t start)
116 {
117 return start + 6 < string.length() && string[start] == '<'
118 && WTF::toASCIILowerUnchecked(string[start + 1]) == 's'
119 && WTF::toASCIILowerUnchecked(string[start + 2]) == 'c'
120 && WTF::toASCIILowerUnchecked(string[start + 3]) == 'r'
121 && WTF::toASCIILowerUnchecked(string[start + 4]) == 'i'
122 && WTF::toASCIILowerUnchecked(string[start + 5]) == 'p'
123 && WTF::toASCIILowerUnchecked(string[start + 6]) == 't';
112 } 124 }
113 125
114 // If other files need this, we should move this to core/html/parser/HTMLParserI dioms.h 126 // If other files need this, we should move this to core/html/parser/HTMLParserI dioms.h
115 template<size_t inlineCapacity> 127 template<size_t inlineCapacity>
116 bool threadSafeMatch(const Vector<UChar, inlineCapacity>& vector, const Qualifie dName& qname) 128 bool threadSafeMatch(const Vector<UChar, inlineCapacity>& vector, const Qualifie dName& qname)
117 { 129 {
118 return equalIgnoringNullity(vector, qname.localName().impl()); 130 return equalIgnoringNullity(vector, qname.localName().impl());
119 } 131 }
120 132
121 static bool hasName(const HTMLToken& token, const QualifiedName& name) 133 static bool hasName(const HTMLToken& token, const QualifiedName& name)
(...skipping 520 matching lines...) Expand 10 before | Expand all | Expand 10 after
642 } 654 }
643 return canonicalize(decodedSnippet); 655 return canonicalize(decodedSnippet);
644 } 656 }
645 657
646 String XSSAuditor::decodedSnippetForJavaScript(const FilterTokenRequest& request ) 658 String XSSAuditor::decodedSnippetForJavaScript(const FilterTokenRequest& request )
647 { 659 {
648 String string = request.sourceTracker.sourceForToken(request.token); 660 String string = request.sourceTracker.sourceForToken(request.token);
649 size_t startPosition = 0; 661 size_t startPosition = 0;
650 size_t endPosition = string.length(); 662 size_t endPosition = string.length();
651 size_t foundPosition = kNotFound; 663 size_t foundPosition = kNotFound;
664 size_t lastNonSpacePosition = kNotFound;
652 665
653 // Skip over initial comments to find start of code. 666 // Skip over initial comments to find start of code.
654 while (startPosition < endPosition) { 667 while (startPosition < endPosition) {
655 while (startPosition < endPosition && isHTMLSpace<UChar>(string[startPos ition])) 668 while (startPosition < endPosition && isHTMLSpace<UChar>(string[startPos ition]))
656 startPosition++; 669 startPosition++;
657 670
658 // Under SVG/XML rules, only HTML comment syntax matters and the parser returns 671 // Under SVG/XML rules, only HTML comment syntax matters and the parser returns
659 // these as a separate comment tokens. Having consumed whitespace, we ne ed not look 672 // these as a separate comment tokens. Having consumed whitespace, we ne ed not look
660 // further for these. 673 // further for these.
661 if (request.shouldAllowCDATA) 674 if (request.shouldAllowCDATA)
662 break; 675 break;
663 676
664 // Under HTML rules, both the HTML and JS comment synatx matters, and th e HTML 677 // Under HTML rules, both the HTML and JS comment synatx matters, and th e HTML
665 // comment ends at the end of the line, not with -->. 678 // comment ends at the end of the line, not with -->.
666 if (startsHTMLCommentAt(string, startPosition) || startsSingleLineCommen tAt(string, startPosition)) { 679 if (startsHTMLCommentAt(string, startPosition) || startsSingleLineCommen tAt(string, startPosition)) {
667 while (startPosition < endPosition && !isJSNewline(string[startPosit ion])) 680 while (startPosition < endPosition && !isJSNewline(string[startPosit ion]))
668 startPosition++; 681 startPosition++;
669 } else if (startsMultiLineCommentAt(string, startPosition)) { 682 } else if (startsMultiLineCommentAt(string, startPosition)) {
670 if (startPosition + 2 < endPosition && (foundPosition = string.find( "*/", startPosition + 2)) != kNotFound) 683 if (startPosition + 2 < endPosition && (foundPosition = string.find( "*/", startPosition + 2)) != kNotFound)
671 startPosition = foundPosition + 2; 684 startPosition = foundPosition + 2;
672 else 685 else
673 startPosition = endPosition; 686 startPosition = endPosition;
674 } else 687 } else
675 break; 688 break;
676 } 689 }
677 690
678 String result; 691 String result;
679 while (startPosition < endPosition && !result.length()) { 692 while (startPosition < endPosition && !result.length()) {
680 // Stop at next comment (using the same rules as above for SVG/XML vs HT ML), when we 693 // Stop at next comment (using the same rules as above for SVG/XML vs HT ML), when we encounter a comma,
681 // encounter a comma, or when we exceed the maximum length target. The comma rule 694 // when we hit an opening <script> tag, or when we exceed the maximum le ngth target. The comma rule
682 // covers a common parameter concatenation case performed by some webser vers. 695 // covers a common parameter concatenation case performed by some web se rvers.
683 // After hitting the length target, we can only stop at a point where we know we are 696 lastNonSpacePosition = kNotFound;
684 // not in the middle of a %-escape sequence. For the sake of simplicity, approximate
685 // not stopping inside a (possibly multiply encoded) %-esacpe sequence b y breaking on
686 // whitespace only. We should have enough text in these cases to avoid f alse positives.
687 for (foundPosition = startPosition; foundPosition < endPosition; foundPo sition++) { 697 for (foundPosition = startPosition; foundPosition < endPosition; foundPo sition++) {
688 if (!request.shouldAllowCDATA) { 698 if (!request.shouldAllowCDATA) {
689 if (startsSingleLineCommentAt(string, foundPosition) || startsMu ltiLineCommentAt(string, foundPosition)) { 699 if (startsSingleLineCommentAt(string, foundPosition) || startsMu ltiLineCommentAt(string, foundPosition)) {
690 foundPosition += 2; 700 foundPosition += 2;
691 break; 701 break;
692 } 702 }
693 if (startsHTMLCommentAt(string, foundPosition)) { 703 if (startsHTMLCommentAt(string, foundPosition)) {
694 foundPosition += 4; 704 foundPosition += 4;
695 break; 705 break;
696 } 706 }
697 } 707 }
698 if (string[foundPosition] == ',' || (foundPosition > startPosition + kMaximumFragmentLengthTarget && isHTMLSpace<UChar>(string[foundPosition]))) { 708 if (string[foundPosition] == ',')
709 break;
710
711 if (lastNonSpacePosition != kNotFound && startsOpeningScriptTagAt(st ring, foundPosition)) {
712 foundPosition = lastNonSpacePosition;
699 break; 713 break;
700 } 714 }
715
716 if (foundPosition > startPosition + kMaximumFragmentLengthTarget) {
717 // After hitting the length target, we can only stop at a point where we know we are
718 // not in the middle of a %-escape sequence. For the sake of sim plicity, approximate
719 // not stopping inside a (possibly multiply encoded) %-escape se quence by breaking on
720 // whitespace only. We should have enough text in these cases to avoid false positives.
721 if (isHTMLSpace<UChar>(string[foundPosition]))
722 break;
723 }
724
725 if (!isHTMLSpace<UChar>(string[foundPosition]))
726 lastNonSpacePosition = foundPosition;
701 } 727 }
702 728
703 result = canonicalize(fullyDecodeString(string.substring(startPosition, foundPosition - startPosition), m_encoding)); 729 result = canonicalize(fullyDecodeString(string.substring(startPosition, foundPosition - startPosition), m_encoding));
704 startPosition = foundPosition + 1; 730 startPosition = foundPosition + 1;
705 } 731 }
706 return result; 732 return result;
707 } 733 }
708 734
709 bool XSSAuditor::isContainedInRequest(const String& decodedSnippet) 735 bool XSSAuditor::isContainedInRequest(const String& decodedSnippet)
710 { 736 {
(...skipping 29 matching lines...) Expand all
740 766
741 bool XSSAuditor::isSafeToSendToAnotherThread() const 767 bool XSSAuditor::isSafeToSendToAnotherThread() const
742 { 768 {
743 return m_documentURL.isSafeToSendToAnotherThread() 769 return m_documentURL.isSafeToSendToAnotherThread()
744 && m_decodedURL.isSafeToSendToAnotherThread() 770 && m_decodedURL.isSafeToSendToAnotherThread()
745 && m_decodedHTTPBody.isSafeToSendToAnotherThread() 771 && m_decodedHTTPBody.isSafeToSendToAnotherThread()
746 && m_httpBodyAsString.isSafeToSendToAnotherThread(); 772 && m_httpBodyAsString.isSafeToSendToAnotherThread();
747 } 773 }
748 774
749 } // namespace WebCore 775 } // namespace WebCore
OLDNEW
« no previous file with comments | « LayoutTests/http/tests/security/xssAuditor/script-tag-near-start-expected.txt ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698