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

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: guard against no lastNonSpacePosition found. 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-expression-follows-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 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
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] == '*');
112 } 113 }
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' && WTF::toASCIILow erUnchecked(string[start+2]) == 'c'
dbates 2014/03/20 17:39:35 Nit: There should be space characters on either si
119 && WTF::toASCIILowerUnchecked(string[start+3]) == 'r' && WTF::toASCIILow erUnchecked(string[start+4]) == 'i'
120 && WTF::toASCIILowerUnchecked(string[start+5]) == 'p' && WTF::toASCIILow erUnchecked(string[start+6]) == 't';
121 }
122
114 // If other files need this, we should move this to core/html/parser/HTMLParserI dioms.h 123 // If other files need this, we should move this to core/html/parser/HTMLParserI dioms.h
115 template<size_t inlineCapacity> 124 template<size_t inlineCapacity>
116 bool threadSafeMatch(const Vector<UChar, inlineCapacity>& vector, const Qualifie dName& qname) 125 bool threadSafeMatch(const Vector<UChar, inlineCapacity>& vector, const Qualifie dName& qname)
117 { 126 {
118 return equalIgnoringNullity(vector, qname.localName().impl()); 127 return equalIgnoringNullity(vector, qname.localName().impl());
119 } 128 }
120 129
121 static bool hasName(const HTMLToken& token, const QualifiedName& name) 130 static bool hasName(const HTMLToken& token, const QualifiedName& name)
122 { 131 {
123 return threadSafeMatch(token.name(), name); 132 return threadSafeMatch(token.name(), name);
(...skipping 518 matching lines...) Expand 10 before | Expand all | Expand 10 after
642 } 651 }
643 return canonicalize(decodedSnippet); 652 return canonicalize(decodedSnippet);
644 } 653 }
645 654
646 String XSSAuditor::decodedSnippetForJavaScript(const FilterTokenRequest& request ) 655 String XSSAuditor::decodedSnippetForJavaScript(const FilterTokenRequest& request )
647 { 656 {
648 String string = request.sourceTracker.sourceForToken(request.token); 657 String string = request.sourceTracker.sourceForToken(request.token);
649 size_t startPosition = 0; 658 size_t startPosition = 0;
650 size_t endPosition = string.length(); 659 size_t endPosition = string.length();
651 size_t foundPosition = kNotFound; 660 size_t foundPosition = kNotFound;
661 size_t lastNonSpacePosition = kNotFound;
652 662
653 // Skip over initial comments to find start of code. 663 // Skip over initial comments to find start of code.
654 while (startPosition < endPosition) { 664 while (startPosition < endPosition) {
655 while (startPosition < endPosition && isHTMLSpace<UChar>(string[startPos ition])) 665 while (startPosition < endPosition && isHTMLSpace<UChar>(string[startPos ition]))
656 startPosition++; 666 startPosition++;
657 667
658 // Under SVG/XML rules, only HTML comment syntax matters and the parser returns 668 // 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 669 // these as a separate comment tokens. Having consumed whitespace, we ne ed not look
660 // further for these. 670 // further for these.
661 if (request.shouldAllowCDATA) 671 if (request.shouldAllowCDATA)
662 break; 672 break;
663 673
664 // Under HTML rules, both the HTML and JS comment synatx matters, and th e HTML 674 // 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 -->. 675 // comment ends at the end of the line, not with -->.
666 if (startsHTMLCommentAt(string, startPosition) || startsSingleLineCommen tAt(string, startPosition)) { 676 if (startsHTMLCommentAt(string, startPosition) || startsSingleLineCommen tAt(string, startPosition)) {
667 while (startPosition < endPosition && !isJSNewline(string[startPosit ion])) 677 while (startPosition < endPosition && !isJSNewline(string[startPosit ion]))
668 startPosition++; 678 startPosition++;
669 } else if (startsMultiLineCommentAt(string, startPosition)) { 679 } else if (startsMultiLineCommentAt(string, startPosition)) {
670 if (startPosition + 2 < endPosition && (foundPosition = string.find( "*/", startPosition + 2)) != kNotFound) 680 if (startPosition + 2 < endPosition && (foundPosition = string.find( "*/", startPosition + 2)) != kNotFound)
671 startPosition = foundPosition + 2; 681 startPosition = foundPosition + 2;
672 else 682 else
673 startPosition = endPosition; 683 startPosition = endPosition;
674 } else 684 } else
675 break; 685 break;
676 } 686 }
677 687
678 String result; 688 String result;
679 while (startPosition < endPosition && !result.length()) { 689 while (startPosition < endPosition && !result.length()) {
680 // Stop at next comment (using the same rules as above for SVG/XML vs HT ML), when we 690 // 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 691 // when we hit an opening <script> tag, or when we exceed the maximum l ength target. The comma rule
dbates 2014/03/20 17:39:35 Nit: There are two space characters that precede t
682 // covers a common parameter concatenation case performed by some webser vers. 692 // covers a common parameter concatenation case performed by some webser vers.
dbates 2014/03/20 17:39:35 Nit: Although this isn't part of the patch, "webse
683 // After hitting the length target, we can only stop at a point where we know we are 693 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++) { 694 for (foundPosition = startPosition; foundPosition < endPosition; foundPo sition++) {
688 if (!request.shouldAllowCDATA) { 695 if (!request.shouldAllowCDATA) {
689 if (startsSingleLineCommentAt(string, foundPosition) || startsMu ltiLineCommentAt(string, foundPosition)) { 696 if (startsSingleLineCommentAt(string, foundPosition) || startsMu ltiLineCommentAt(string, foundPosition)) {
690 foundPosition += 2; 697 foundPosition += 2;
691 break; 698 break;
692 } 699 }
693 if (startsHTMLCommentAt(string, foundPosition)) { 700 if (startsHTMLCommentAt(string, foundPosition)) {
694 foundPosition += 4; 701 foundPosition += 4;
695 break; 702 break;
696 } 703 }
697 } 704 }
698 if (string[foundPosition] == ',' || (foundPosition > startPosition + kMaximumFragmentLengthTarget && isHTMLSpace<UChar>(string[foundPosition]))) { 705 if (string[foundPosition] == ',')
706 break;
707
708 if (lastNonSpacePosition != kNotFound && startsOpeningScriptTagAt(st ring, foundPosition)) {
709 foundPosition = lastNonSpacePosition;
dbates 2014/03/20 17:39:35 The coverage included in this patch is sufficient.
699 break; 710 break;
700 } 711 }
712
713 if (foundPosition > startPosition + kMaximumFragmentLengthTarget) {
714 // After hitting the length target, we can only stop at a point where we know we are
715 // not in the middle of a %-escape sequence. For the sake of sim plicity, approximate
716 // not stopping inside a (possibly multiply encoded) %-esacpe se quence by breaking on
dbates 2014/03/20 17:39:35 Nit: esacpe => escape
717 // whitespace only. We should have enough text in these cases to avoid false positives.
718 if (isHTMLSpace<UChar>(string[foundPosition]))
719 break;
720 }
721
722 if (!isHTMLSpace<UChar>(string[foundPosition]))
723 lastNonSpacePosition = foundPosition;
701 } 724 }
702 725
703 result = canonicalize(fullyDecodeString(string.substring(startPosition, foundPosition - startPosition), m_encoding)); 726 result = canonicalize(fullyDecodeString(string.substring(startPosition, foundPosition - startPosition), m_encoding));
704 startPosition = foundPosition + 1; 727 startPosition = foundPosition + 1;
705 } 728 }
706 return result; 729 return result;
707 } 730 }
708 731
709 bool XSSAuditor::isContainedInRequest(const String& decodedSnippet) 732 bool XSSAuditor::isContainedInRequest(const String& decodedSnippet)
710 { 733 {
(...skipping 29 matching lines...) Expand all
740 763
741 bool XSSAuditor::isSafeToSendToAnotherThread() const 764 bool XSSAuditor::isSafeToSendToAnotherThread() const
742 { 765 {
743 return m_documentURL.isSafeToSendToAnotherThread() 766 return m_documentURL.isSafeToSendToAnotherThread()
744 && m_decodedURL.isSafeToSendToAnotherThread() 767 && m_decodedURL.isSafeToSendToAnotherThread()
745 && m_decodedHTTPBody.isSafeToSendToAnotherThread() 768 && m_decodedHTTPBody.isSafeToSendToAnotherThread()
746 && m_httpBodyAsString.isSafeToSendToAnotherThread(); 769 && m_httpBodyAsString.isSafeToSendToAnotherThread();
747 } 770 }
748 771
749 } // namespace WebCore 772 } // namespace WebCore
OLDNEW
« no previous file with comments | « LayoutTests/http/tests/security/xssAuditor/script-tag-expression-follows-expected.txt ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698