OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // FIXME(dominicc): Poor confused check-webkit-style demands Attribute.h here. | 5 // FIXME(dominicc): Poor confused check-webkit-style demands Attribute.h here. |
6 #include "core/dom/Attribute.h" | 6 #include "core/dom/Attribute.h" |
7 | 7 |
8 #include "core/HTMLNames.h" | 8 #include "core/HTMLNames.h" |
9 #include "core/SVGNames.h" | 9 #include "core/SVGNames.h" |
10 #include "core/XLinkNames.h" | 10 #include "core/XLinkNames.h" |
11 #include "core/clipboard/Pasteboard.h" | 11 #include "core/clipboard/Pasteboard.h" |
12 #include "core/dom/QualifiedName.h" | 12 #include "core/dom/QualifiedName.h" |
13 #include "core/editing/Editor.h" | 13 #include "core/editing/Editor.h" |
14 #include "core/editing/SelectionType.h" | 14 #include "core/editing/SelectionType.h" |
15 #include "core/editing/VisibleSelection.h" | 15 #include "core/editing/VisibleSelection.h" |
16 #include "core/html/HTMLElement.h" | 16 #include "core/html/HTMLElement.h" |
17 #include "core/svg/SVGAElement.h" | 17 #include "core/svg/SVGAElement.h" |
18 #include "core/svg/SVGAnimateElement.h" | 18 #include "core/svg/SVGAnimateElement.h" |
19 #include "core/svg/SVGDiscardElement.h" | 19 #include "core/svg/SVGDiscardElement.h" |
20 #include "core/svg/SVGSetElement.h" | 20 #include "core/svg/SVGSetElement.h" |
21 #include "core/svg/animation/SVGSMILElement.h" | 21 #include "core/svg/animation/SVGSMILElement.h" |
22 #include "core/svg/properties/SVGPropertyInfo.h" | 22 #include "core/svg/properties/SVGPropertyInfo.h" |
23 #include "core/testing/DummyPageHolder.h" | 23 #include "core/testing/DummyPageHolder.h" |
24 #include "platform/geometry/IntSize.h" | 24 #include "platform/geometry/IntSize.h" |
25 #include "platform/weborigin/KURL.h" | 25 #include "platform/weborigin/KURL.h" |
26 #include "testing/gtest/include/gtest/gtest.h" | 26 #include "testing/gtest/include/gtest/gtest.h" |
27 #include "wtf/Vector.h" | 27 #include "wtf/Vector.h" |
28 #include "wtf/text/AtomicString.h" | 28 #include "wtf/text/AtomicString.h" |
29 #include "wtf/text/WTFString.h" | 29 #include "wtf/text/WTFString.h" |
30 #include <memory> | |
31 | 30 |
32 // Test that SVG content with JavaScript URLs is sanitized by removing | 31 // Test that SVG content with JavaScript URLs is sanitized by removing |
33 // the URLs. This sanitization happens when the content is pasted or | 32 // the URLs. This sanitization happens when the content is pasted or |
34 // drag-dropped into an editable element. | 33 // drag-dropped into an editable element. |
35 // | 34 // |
36 // There are two vectors for JavaScript URLs in SVG content: | 35 // There are two vectors for JavaScript URLs in SVG content: |
37 // | 36 // |
38 // 1. Attributes, for example xlink:href/href in an <svg:a> element. | 37 // 1. Attributes, for example xlink:href/href in an <svg:a> element. |
39 // 2. Animations which set those attributes, for example | 38 // 2. Animations which set those attributes, for example |
40 // <animate attributeName="xlink:href" values="javascript:... | 39 // <animate attributeName="xlink:href" values="javascript:... |
(...skipping 29 matching lines...) Expand all Loading... |
70 | 69 |
71 return body->innerHTML(); | 70 return body->innerHTML(); |
72 } | 71 } |
73 | 72 |
74 // Integration tests. | 73 // Integration tests. |
75 | 74 |
76 TEST( | 75 TEST( |
77 UnsafeSVGAttributeSanitizationTest, | 76 UnsafeSVGAttributeSanitizationTest, |
78 pasteAnchor_javaScriptHrefIsStripped) | 77 pasteAnchor_javaScriptHrefIsStripped) |
79 { | 78 { |
80 std::unique_ptr<DummyPageHolder> pageHolder = DummyPageHolder::create(IntSiz
e(1, 1)); | 79 OwnPtr<DummyPageHolder> pageHolder = DummyPageHolder::create(IntSize(1, 1)); |
81 static const char unsafeContent[] = | 80 static const char unsafeContent[] = |
82 "<svg xmlns='http://www.w3.org/2000/svg' " | 81 "<svg xmlns='http://www.w3.org/2000/svg' " |
83 " width='1cm' height='1cm'>" | 82 " width='1cm' height='1cm'>" |
84 " <a href='javascript:alert()'></a>" | 83 " <a href='javascript:alert()'></a>" |
85 "</svg>"; | 84 "</svg>"; |
86 String sanitizedContent = | 85 String sanitizedContent = |
87 contentAfterPastingHTML(pageHolder.get(), unsafeContent); | 86 contentAfterPastingHTML(pageHolder.get(), unsafeContent); |
88 | 87 |
89 EXPECT_TRUE(sanitizedContent.contains("</a>")) << | 88 EXPECT_TRUE(sanitizedContent.contains("</a>")) << |
90 "We should have pasted *something*; the document is: " << | 89 "We should have pasted *something*; the document is: " << |
91 sanitizedContent.utf8().data(); | 90 sanitizedContent.utf8().data(); |
92 EXPECT_FALSE(sanitizedContent.contains(":alert()")) << | 91 EXPECT_FALSE(sanitizedContent.contains(":alert()")) << |
93 "The JavaScript URL is unsafe and should have been stripped; " | 92 "The JavaScript URL is unsafe and should have been stripped; " |
94 "instead: " << | 93 "instead: " << |
95 sanitizedContent.utf8().data(); | 94 sanitizedContent.utf8().data(); |
96 } | 95 } |
97 | 96 |
98 TEST( | 97 TEST( |
99 UnsafeSVGAttributeSanitizationTest, | 98 UnsafeSVGAttributeSanitizationTest, |
100 pasteAnchor_javaScriptXlinkHrefIsStripped) | 99 pasteAnchor_javaScriptXlinkHrefIsStripped) |
101 { | 100 { |
102 std::unique_ptr<DummyPageHolder> pageHolder = DummyPageHolder::create(IntSiz
e(1, 1)); | 101 OwnPtr<DummyPageHolder> pageHolder = DummyPageHolder::create(IntSize(1, 1)); |
103 static const char unsafeContent[] = | 102 static const char unsafeContent[] = |
104 "<svg xmlns='http://www.w3.org/2000/svg' " | 103 "<svg xmlns='http://www.w3.org/2000/svg' " |
105 " xmlns:xlink='http://www.w3.org/1999/xlink'" | 104 " xmlns:xlink='http://www.w3.org/1999/xlink'" |
106 " width='1cm' height='1cm'>" | 105 " width='1cm' height='1cm'>" |
107 " <a xlink:href='javascript:alert()'></a>" | 106 " <a xlink:href='javascript:alert()'></a>" |
108 "</svg>"; | 107 "</svg>"; |
109 String sanitizedContent = | 108 String sanitizedContent = |
110 contentAfterPastingHTML(pageHolder.get(), unsafeContent); | 109 contentAfterPastingHTML(pageHolder.get(), unsafeContent); |
111 | 110 |
112 EXPECT_TRUE(sanitizedContent.contains("</a>")) << | 111 EXPECT_TRUE(sanitizedContent.contains("</a>")) << |
113 "We should have pasted *something*; the document is: " << | 112 "We should have pasted *something*; the document is: " << |
114 sanitizedContent.utf8().data(); | 113 sanitizedContent.utf8().data(); |
115 EXPECT_FALSE(sanitizedContent.contains(":alert()")) << | 114 EXPECT_FALSE(sanitizedContent.contains(":alert()")) << |
116 "The JavaScript URL is unsafe and should have been stripped; " | 115 "The JavaScript URL is unsafe and should have been stripped; " |
117 "instead: " << | 116 "instead: " << |
118 sanitizedContent.utf8().data(); | 117 sanitizedContent.utf8().data(); |
119 } | 118 } |
120 | 119 |
121 TEST( | 120 TEST( |
122 UnsafeSVGAttributeSanitizationTest, | 121 UnsafeSVGAttributeSanitizationTest, |
123 pasteAnchor_javaScriptHrefIsStripped_caseAndEntityInProtocol) | 122 pasteAnchor_javaScriptHrefIsStripped_caseAndEntityInProtocol) |
124 { | 123 { |
125 std::unique_ptr<DummyPageHolder> pageHolder = DummyPageHolder::create(IntSiz
e(1, 1)); | 124 OwnPtr<DummyPageHolder> pageHolder = DummyPageHolder::create(IntSize(1, 1)); |
126 static const char unsafeContent[] = | 125 static const char unsafeContent[] = |
127 "<svg xmlns='http://www.w3.org/2000/svg' " | 126 "<svg xmlns='http://www.w3.org/2000/svg' " |
128 " width='1cm' height='1cm'>" | 127 " width='1cm' height='1cm'>" |
129 " <a href='jAvascriPT:alert()'></a>" | 128 " <a href='jAvascriPT:alert()'></a>" |
130 "</svg>"; | 129 "</svg>"; |
131 String sanitizedContent = | 130 String sanitizedContent = |
132 contentAfterPastingHTML(pageHolder.get(), unsafeContent); | 131 contentAfterPastingHTML(pageHolder.get(), unsafeContent); |
133 | 132 |
134 EXPECT_TRUE(sanitizedContent.contains("</a>")) << | 133 EXPECT_TRUE(sanitizedContent.contains("</a>")) << |
135 "We should have pasted *something*; the document is: " << | 134 "We should have pasted *something*; the document is: " << |
136 sanitizedContent.utf8().data(); | 135 sanitizedContent.utf8().data(); |
137 EXPECT_FALSE(sanitizedContent.contains(":alert()")) << | 136 EXPECT_FALSE(sanitizedContent.contains(":alert()")) << |
138 "The JavaScript URL is unsafe and should have been stripped; " | 137 "The JavaScript URL is unsafe and should have been stripped; " |
139 "instead: " << | 138 "instead: " << |
140 sanitizedContent.utf8().data(); | 139 sanitizedContent.utf8().data(); |
141 } | 140 } |
142 | 141 |
143 TEST( | 142 TEST( |
144 UnsafeSVGAttributeSanitizationTest, | 143 UnsafeSVGAttributeSanitizationTest, |
145 pasteAnchor_javaScriptXlinkHrefIsStripped_caseAndEntityInProtocol) | 144 pasteAnchor_javaScriptXlinkHrefIsStripped_caseAndEntityInProtocol) |
146 { | 145 { |
147 std::unique_ptr<DummyPageHolder> pageHolder = DummyPageHolder::create(IntSiz
e(1, 1)); | 146 OwnPtr<DummyPageHolder> pageHolder = DummyPageHolder::create(IntSize(1, 1)); |
148 static const char unsafeContent[] = | 147 static const char unsafeContent[] = |
149 "<svg xmlns='http://www.w3.org/2000/svg' " | 148 "<svg xmlns='http://www.w3.org/2000/svg' " |
150 " xmlns:xlink='http://www.w3.org/1999/xlink'" | 149 " xmlns:xlink='http://www.w3.org/1999/xlink'" |
151 " width='1cm' height='1cm'>" | 150 " width='1cm' height='1cm'>" |
152 " <a xlink:href='jAvascriPT:alert()'></a>" | 151 " <a xlink:href='jAvascriPT:alert()'></a>" |
153 "</svg>"; | 152 "</svg>"; |
154 String sanitizedContent = | 153 String sanitizedContent = |
155 contentAfterPastingHTML(pageHolder.get(), unsafeContent); | 154 contentAfterPastingHTML(pageHolder.get(), unsafeContent); |
156 | 155 |
157 EXPECT_TRUE(sanitizedContent.contains("</a>")) << | 156 EXPECT_TRUE(sanitizedContent.contains("</a>")) << |
158 "We should have pasted *something*; the document is: " << | 157 "We should have pasted *something*; the document is: " << |
159 sanitizedContent.utf8().data(); | 158 sanitizedContent.utf8().data(); |
160 EXPECT_FALSE(sanitizedContent.contains(":alert()")) << | 159 EXPECT_FALSE(sanitizedContent.contains(":alert()")) << |
161 "The JavaScript URL is unsafe and should have been stripped; " | 160 "The JavaScript URL is unsafe and should have been stripped; " |
162 "instead: " << | 161 "instead: " << |
163 sanitizedContent.utf8().data(); | 162 sanitizedContent.utf8().data(); |
164 } | 163 } |
165 | 164 |
166 TEST( | 165 TEST( |
167 UnsafeSVGAttributeSanitizationTest, | 166 UnsafeSVGAttributeSanitizationTest, |
168 pasteAnchor_javaScriptHrefIsStripped_entityWithoutSemicolonInProtocol) | 167 pasteAnchor_javaScriptHrefIsStripped_entityWithoutSemicolonInProtocol) |
169 { | 168 { |
170 std::unique_ptr<DummyPageHolder> pageHolder = DummyPageHolder::create(IntSiz
e(1, 1)); | 169 OwnPtr<DummyPageHolder> pageHolder = DummyPageHolder::create(IntSize(1, 1)); |
171 static const char unsafeContent[] = | 170 static const char unsafeContent[] = |
172 "<svg xmlns='http://www.w3.org/2000/svg' " | 171 "<svg xmlns='http://www.w3.org/2000/svg' " |
173 " width='1cm' height='1cm'>" | 172 " width='1cm' height='1cm'>" |
174 " <a href='javascript:alert()'></a>" | 173 " <a href='javascript:alert()'></a>" |
175 "</svg>"; | 174 "</svg>"; |
176 String sanitizedContent = | 175 String sanitizedContent = |
177 contentAfterPastingHTML(pageHolder.get(), unsafeContent); | 176 contentAfterPastingHTML(pageHolder.get(), unsafeContent); |
178 | 177 |
179 EXPECT_TRUE(sanitizedContent.contains("</a>")) << | 178 EXPECT_TRUE(sanitizedContent.contains("</a>")) << |
180 "We should have pasted *something*; the document is: " << | 179 "We should have pasted *something*; the document is: " << |
181 sanitizedContent.utf8().data(); | 180 sanitizedContent.utf8().data(); |
182 EXPECT_FALSE(sanitizedContent.contains(":alert()")) << | 181 EXPECT_FALSE(sanitizedContent.contains(":alert()")) << |
183 "The JavaScript URL is unsafe and should have been stripped; " | 182 "The JavaScript URL is unsafe and should have been stripped; " |
184 "instead: " << | 183 "instead: " << |
185 sanitizedContent.utf8().data(); | 184 sanitizedContent.utf8().data(); |
186 } | 185 } |
187 | 186 |
188 TEST( | 187 TEST( |
189 UnsafeSVGAttributeSanitizationTest, | 188 UnsafeSVGAttributeSanitizationTest, |
190 pasteAnchor_javaScriptXlinkHrefIsStripped_entityWithoutSemicolonInProtocol) | 189 pasteAnchor_javaScriptXlinkHrefIsStripped_entityWithoutSemicolonInProtocol) |
191 { | 190 { |
192 std::unique_ptr<DummyPageHolder> pageHolder = DummyPageHolder::create(IntSiz
e(1, 1)); | 191 OwnPtr<DummyPageHolder> pageHolder = DummyPageHolder::create(IntSize(1, 1)); |
193 static const char unsafeContent[] = | 192 static const char unsafeContent[] = |
194 "<svg xmlns='http://www.w3.org/2000/svg' " | 193 "<svg xmlns='http://www.w3.org/2000/svg' " |
195 " xmlns:xlink='http://www.w3.org/1999/xlink'" | 194 " xmlns:xlink='http://www.w3.org/1999/xlink'" |
196 " width='1cm' height='1cm'>" | 195 " width='1cm' height='1cm'>" |
197 " <a xlink:href='javascript:alert()'></a>" | 196 " <a xlink:href='javascript:alert()'></a>" |
198 "</svg>"; | 197 "</svg>"; |
199 String sanitizedContent = | 198 String sanitizedContent = |
200 contentAfterPastingHTML(pageHolder.get(), unsafeContent); | 199 contentAfterPastingHTML(pageHolder.get(), unsafeContent); |
201 | 200 |
202 EXPECT_TRUE(sanitizedContent.contains("</a>")) << | 201 EXPECT_TRUE(sanitizedContent.contains("</a>")) << |
203 "We should have pasted *something*; the document is: " << | 202 "We should have pasted *something*; the document is: " << |
204 sanitizedContent.utf8().data(); | 203 sanitizedContent.utf8().data(); |
205 EXPECT_FALSE(sanitizedContent.contains(":alert()")) << | 204 EXPECT_FALSE(sanitizedContent.contains(":alert()")) << |
206 "The JavaScript URL is unsafe and should have been stripped; " | 205 "The JavaScript URL is unsafe and should have been stripped; " |
207 "instead: " << | 206 "instead: " << |
208 sanitizedContent.utf8().data(); | 207 sanitizedContent.utf8().data(); |
209 } | 208 } |
210 | 209 |
211 // Other sanitization integration tests are layout tests that use | 210 // Other sanitization integration tests are layout tests that use |
212 // document.execCommand('Copy') to source content that they later | 211 // document.execCommand('Copy') to source content that they later |
213 // paste. However SVG animation elements are not serialized when | 212 // paste. However SVG animation elements are not serialized when |
214 // copying, which means we can't test sanitizing these attributes in | 213 // copying, which means we can't test sanitizing these attributes in |
215 // layout tests: there is nowhere to source the unsafe content from. | 214 // layout tests: there is nowhere to source the unsafe content from. |
216 TEST( | 215 TEST( |
217 UnsafeSVGAttributeSanitizationTest, | 216 UnsafeSVGAttributeSanitizationTest, |
218 pasteAnimatedAnchor_javaScriptHrefIsStripped_caseAndEntityInProtocol) | 217 pasteAnimatedAnchor_javaScriptHrefIsStripped_caseAndEntityInProtocol) |
219 { | 218 { |
220 std::unique_ptr<DummyPageHolder> pageHolder = DummyPageHolder::create(IntSiz
e(1, 1)); | 219 OwnPtr<DummyPageHolder> pageHolder = DummyPageHolder::create(IntSize(1, 1)); |
221 static const char unsafeContent[] = | 220 static const char unsafeContent[] = |
222 "<svg xmlns='http://www.w3.org/2000/svg' " | 221 "<svg xmlns='http://www.w3.org/2000/svg' " |
223 " width='1cm' height='1cm'>" | 222 " width='1cm' height='1cm'>" |
224 " <a href='https://www.google.com/'>" | 223 " <a href='https://www.google.com/'>" |
225 " <animate attributeName='href' values='evil;JaVaSCRIpT:alert()'>
" | 224 " <animate attributeName='href' values='evil;JaVaSCRIpT:alert()'>
" |
226 " </a>" | 225 " </a>" |
227 "</svg>"; | 226 "</svg>"; |
228 String sanitizedContent = | 227 String sanitizedContent = |
229 contentAfterPastingHTML(pageHolder.get(), unsafeContent); | 228 contentAfterPastingHTML(pageHolder.get(), unsafeContent); |
230 | 229 |
231 EXPECT_TRUE(sanitizedContent.contains("<a href=\"https://www.goo")) << | 230 EXPECT_TRUE(sanitizedContent.contains("<a href=\"https://www.goo")) << |
232 "We should have pasted *something*; the document is: " << | 231 "We should have pasted *something*; the document is: " << |
233 sanitizedContent.utf8().data(); | 232 sanitizedContent.utf8().data(); |
234 EXPECT_FALSE(sanitizedContent.contains(":alert()")) << | 233 EXPECT_FALSE(sanitizedContent.contains(":alert()")) << |
235 "The JavaScript URL is unsafe and should have been stripped; " | 234 "The JavaScript URL is unsafe and should have been stripped; " |
236 "instead: " << | 235 "instead: " << |
237 sanitizedContent.utf8().data(); | 236 sanitizedContent.utf8().data(); |
238 } | 237 } |
239 | 238 |
240 TEST( | 239 TEST( |
241 UnsafeSVGAttributeSanitizationTest, | 240 UnsafeSVGAttributeSanitizationTest, |
242 pasteAnimatedAnchor_javaScriptXlinkHrefIsStripped_caseAndEntityInProtocol) | 241 pasteAnimatedAnchor_javaScriptXlinkHrefIsStripped_caseAndEntityInProtocol) |
243 { | 242 { |
244 std::unique_ptr<DummyPageHolder> pageHolder = DummyPageHolder::create(IntSiz
e(1, 1)); | 243 OwnPtr<DummyPageHolder> pageHolder = DummyPageHolder::create(IntSize(1, 1)); |
245 static const char unsafeContent[] = | 244 static const char unsafeContent[] = |
246 "<svg xmlns='http://www.w3.org/2000/svg' " | 245 "<svg xmlns='http://www.w3.org/2000/svg' " |
247 " xmlns:xlink='http://www.w3.org/1999/xlink'" | 246 " xmlns:xlink='http://www.w3.org/1999/xlink'" |
248 " width='1cm' height='1cm'>" | 247 " width='1cm' height='1cm'>" |
249 " <a xlink:href='https://www.google.com/'>" | 248 " <a xlink:href='https://www.google.com/'>" |
250 " <animate xmlns:ng='http://www.w3.org/1999/xlink' " | 249 " <animate xmlns:ng='http://www.w3.org/1999/xlink' " |
251 " attributeName='ng:href' values='evil;JaVaSCRIpT:alert(
)'>" | 250 " attributeName='ng:href' values='evil;JaVaSCRIpT:alert(
)'>" |
252 " </a>" | 251 " </a>" |
253 "</svg>"; | 252 "</svg>"; |
254 String sanitizedContent = | 253 String sanitizedContent = |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
406 Attribute fineAttribute(SVGNames::fromAttr, "hello, world!"); | 405 Attribute fineAttribute(SVGNames::fromAttr, "hello, world!"); |
407 Document* document = Document::create(); | 406 Document* document = Document::create(); |
408 Element* element = SVGSetElement::create(*document); | 407 Element* element = SVGSetElement::create(*document); |
409 EXPECT_FALSE( | 408 EXPECT_FALSE( |
410 element->isSVGAnimationAttributeSettingJavaScriptURL(fineAttribute)) << | 409 element->isSVGAnimationAttributeSettingJavaScriptURL(fineAttribute)) << |
411 "The animate element should not identify a 'from' attribute with an " | 410 "The animate element should not identify a 'from' attribute with an " |
412 "innocuous value as setting a JavaScript URL."; | 411 "innocuous value as setting a JavaScript URL."; |
413 } | 412 } |
414 | 413 |
415 } // namespace blink | 414 } // namespace blink |
OLD | NEW |