Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "config.h" | |
| 6 // FIXME(dominicc): Poor confused check-webkit-style demands Attribute.h here. | |
| 7 #include "core/dom/Attribute.h" | |
| 8 | |
| 9 #include "core/HTMLNames.h" | |
| 10 #include "core/SVGNames.h" | |
| 11 #include "core/XLinkNames.h" | |
| 12 #include "core/clipboard/Pasteboard.h" | |
| 13 #include "core/dom/QualifiedName.h" | |
| 14 #include "core/editing/Editor.h" | |
| 15 #include "core/editing/SelectionType.h" | |
| 16 #include "core/editing/VisibleSelection.h" | |
| 17 #include "core/html/HTMLElement.h" | |
| 18 #include "core/svg/SVGAElement.h" | |
| 19 #include "core/svg/SVGAnimateElement.h" | |
| 20 #include "core/svg/SVGDiscardElement.h" | |
| 21 #include "core/svg/SVGSetElement.h" | |
| 22 #include "core/svg/animation/SVGSMILElement.h" | |
| 23 #include "core/svg/properties/SVGPropertyInfo.h" | |
| 24 #include "core/testing/DummyPageHolder.h" | |
| 25 #include "platform/geometry/IntSize.h" | |
| 26 #include "platform/weborigin/KURL.h" | |
| 27 #include "wtf/Vector.h" | |
| 28 #include "wtf/text/AtomicString.h" | |
| 29 #include "wtf/text/WTFString.h" | |
| 30 #include <gtest/gtest.h> | |
| 31 | |
| 32 namespace blink { | |
| 33 | |
| 34 // The following SVG elements, although related to animation, cannot | |
| 35 // set JavaScript URLs: | |
| 36 // | |
| 37 // - 'discard' can only remove elements, not set their attributes | |
| 38 // - 'animateMotion' does not use attribute name and produces floats | |
| 39 // - 'animateTransform' can only animate transform lists | |
| 40 | |
| 41 // Pastes htmlToPaste into the body of pageHolder's document, and | |
| 42 // returns the new content of the body. | |
| 43 String contentAfterPastingHTML( | |
| 44 DummyPageHolder* pageHolder, | |
| 45 const char* htmlToPaste) | |
| 46 { | |
| 47 LocalFrame& frame = pageHolder->frame(); | |
| 48 HTMLElement* body = pageHolder->document().body(); | |
| 49 | |
| 50 // Make the body editable, and put the caret in it. | |
| 51 body->setAttribute(HTMLNames::contenteditableAttr, "true"); | |
| 52 frame.selection().setSelection(VisibleSelection::selectionFromContentsOfNode (body)); | |
| 53 EXPECT_EQ(CaretSelection, frame.selection().selectionType()); | |
| 54 EXPECT_TRUE(frame.selection().isContentEditable()) << | |
| 55 "We should be pasting into something editable."; | |
| 56 | |
| 57 Pasteboard pasteboard; | |
| 58 pasteboard.writeHTML(htmlToPaste, blankURL(), "", false); | |
|
dcheng
2015/06/10 09:35:28
Can you remind me how this works for the Blink uni
| |
| 59 frame.editor().pasteWithPasteboard(&pasteboard); | |
|
dcheng
2015/06/10 09:35:28
How about frame.editor().execCommand("paste") to a
| |
| 60 | |
| 61 return body->innerHTML(); | |
| 62 } | |
| 63 | |
| 64 // Integration tests. | |
| 65 // | |
| 66 // Other sanitization integration tests are layout tests that use | |
| 67 // document.execCommand('Copy') to source content that they later | |
| 68 // paste. However SVG animation elements are not serialized when | |
| 69 // copying, which means we can't test sanitizing these attributes in | |
| 70 // layout tests: there is nowhere to source the unsafe content from. | |
| 71 | |
| 72 TEST(UnsafeSVGAttributeSanitizationTest, pasteAnchor_javaScriptHrefIsStripped) | |
| 73 { | |
| 74 OwnPtr<DummyPageHolder> pageHolder = DummyPageHolder::create(IntSize(1, 1)); | |
| 75 const char* unsafeContent = | |
|
dcheng
2015/06/10 09:35:28
Nit: const char* unsafeContent is actually a mutab
Tom Sepez
2015/06/10 17:29:02
nit: Don't you want static const char unsafeConten
| |
| 76 "<svg xmlns='http://www.w3.org/2000/svg' " | |
| 77 " xmlns:xlink='http://www.w3.org/1999/xlink'" | |
| 78 " width='1cm' height='1cm'>" | |
| 79 " <a xlink:href='javascript:alert()'></a>" | |
| 80 "</svg>"; | |
| 81 String sanitizedContent = | |
| 82 contentAfterPastingHTML(pageHolder.get(), unsafeContent); | |
| 83 | |
| 84 EXPECT_TRUE(sanitizedContent.contains("</a>")) << | |
| 85 "We should have pasted *something*; the document is: " << | |
| 86 sanitizedContent.utf8().data(); | |
| 87 EXPECT_FALSE(sanitizedContent.contains("javascript:")) << | |
| 88 "The JavaScript URL is unsafe and should have been stripped; " | |
| 89 "instead: " << | |
| 90 sanitizedContent.utf8().data(); | |
| 91 } | |
| 92 | |
| 93 TEST( | |
| 94 UnsafeSVGAttributeSanitizationTest, | |
|
Tom Sepez
2015/06/10 17:29:02
Nit: funny indentation? I'd expect UnsafeSVGAttrib
| |
| 95 pasteAnimatedAnchor_javaScriptHrefIsStripped) | |
| 96 { | |
| 97 OwnPtr<DummyPageHolder> pageHolder = DummyPageHolder::create(IntSize(1, 1)); | |
| 98 const char* unsafeContent = | |
| 99 "<svg xmlns='http://www.w3.org/2000/svg' " | |
| 100 " xmlns:xlink='http://www.w3.org/1999/xlink'" | |
| 101 " width='1cm' height='1cm'>" | |
| 102 " <a xlink:href='https://www.google.com/'>" | |
| 103 " <animate xmlns:ng='http://www.w3.org/1999/xlink' " | |
| 104 " attributeName='ng:href' values='evil;javascript:alert()'>" | |
|
Tom Sepez
2015/06/10 17:29:02
nit: How about writing JavASCRipT in mixed case in
| |
| 105 " </a>" | |
| 106 "</svg>"; | |
| 107 String sanitizedContent = | |
| 108 contentAfterPastingHTML(pageHolder.get(), unsafeContent); | |
| 109 | |
| 110 EXPECT_TRUE(sanitizedContent.contains("<a xlink:href=\"https://www.goo")) << | |
| 111 "We should have pasted *something*; the document is: " << | |
| 112 sanitizedContent.utf8().data(); | |
| 113 EXPECT_FALSE(sanitizedContent.contains("javascript:")) << | |
| 114 "The JavaScript URL is unsafe and should have been stripped; " | |
| 115 "instead: " << | |
| 116 sanitizedContent.utf8().data(); | |
| 117 } | |
| 118 | |
| 119 // Unit tests | |
| 120 | |
| 121 // stripScriptingAttributes inspects animation attributes for | |
| 122 // javascript: URLs. This check could be defeated if strings supported | |
| 123 // addition. If this test starts failing you must strengthen | |
| 124 // Element::stripScriptingAttributes perhaps to strip all | |
| 125 // isSVGAttributeValueAnimatingAttribute attributes. | |
| 126 TEST(UnsafeSVGAttributeSanitizationTest, stringsShouldNotSupportAddition) | |
| 127 { | |
| 128 RefPtrWillBeRawPtr<Document> document = Document::create(); | |
| 129 RefPtrWillBeRawPtr<SVGElement> target = SVGAElement::create(*document); | |
| 130 RefPtrWillBeRawPtr<SVGAnimateElement> element = SVGAnimateElement::create(*d ocument); | |
| 131 element->setTargetElement(target.get()); | |
| 132 element->setAttributeName(XLinkNames::hrefAttr); | |
| 133 | |
| 134 // Sanity check that xlink:href was identified as a "string" attribute | |
| 135 EXPECT_EQ(AnimatedString, element->animatedPropertyType()); | |
| 136 | |
| 137 EXPECT_FALSE(element->animatedPropertyTypeSupportsAddition()); | |
| 138 } | |
| 139 | |
| 140 TEST( | |
| 141 UnsafeSVGAttributeSanitizationTest, | |
| 142 stripScriptingAttributes_stripsHrefContainingJavascriptURL) | |
| 143 { | |
| 144 Vector<Attribute> attributes; | |
| 145 attributes.append(Attribute(XLinkNames::hrefAttr, "javascript:alert()")); | |
| 146 | |
| 147 RefPtrWillBeRawPtr<Document> document = Document::create(); | |
| 148 RefPtrWillBeRawPtr<Element> element = SVGAElement::create(*document); | |
| 149 element->stripScriptingAttributes(attributes); | |
| 150 | |
| 151 EXPECT_EQ(0ul, attributes.size()) << | |
| 152 "stripScriptingAttributes should strip an 'xlink:href' attribute with " | |
| 153 "a JavaScript URL value."; | |
| 154 } | |
| 155 | |
| 156 TEST( | |
| 157 UnsafeSVGAttributeSanitizationTest, | |
| 158 stripScriptingAttributes_stripsHrefContainingJavascriptURL_alternatePrefix) | |
| 159 { | |
| 160 Vector<Attribute> attributes; | |
| 161 QualifiedName hrefAlternatePrefix( | |
| 162 "foo", "href", XLinkNames::xlinkNamespaceURI); | |
| 163 attributes.append(Attribute(hrefAlternatePrefix, "javascript:alert()")); | |
| 164 | |
| 165 RefPtrWillBeRawPtr<Document> document = Document::create(); | |
| 166 RefPtrWillBeRawPtr<Element> element = SVGAElement::create(*document); | |
| 167 element->stripScriptingAttributes(attributes); | |
| 168 | |
| 169 EXPECT_EQ(0ul, attributes.size()) << | |
| 170 "stripScriptingAttributes should strip an XLink 'href' attribute with " | |
| 171 "a JavaScript URL value, even if the attribute doesn't use the typical " | |
| 172 "'xlink' prefix."; | |
| 173 } | |
| 174 | |
| 175 TEST( | |
| 176 UnsafeSVGAttributeSanitizationTest, | |
| 177 stripScriptingAttributes_stripsAnimationsThatSetJavascriptURLs_from) | |
| 178 { | |
| 179 Vector<Attribute> attributes; | |
| 180 attributes.append(Attribute(SVGNames::fromAttr, "javascript:alert()")); | |
| 181 | |
| 182 RefPtrWillBeRawPtr<Document> document = Document::create(); | |
| 183 RefPtrWillBeRawPtr<Element> element = SVGAnimateElement::create(*document); | |
| 184 element->stripScriptingAttributes(attributes); | |
| 185 | |
| 186 EXPECT_EQ(0ul, attributes.size()) << | |
| 187 "stripScriptingAttributes should strip an animation 'from' attribute " | |
| 188 "with a JavaScript URL value."; | |
| 189 } | |
| 190 | |
| 191 TEST( | |
| 192 UnsafeSVGAttributeSanitizationTest, | |
| 193 stripScriptingAttributes_stripsAnimationsThatSetJavascriptURLs_to) | |
| 194 { | |
| 195 Vector<Attribute> attributes; | |
| 196 attributes.append(Attribute(SVGNames::toAttr, "javascript:window.close()")); | |
| 197 | |
| 198 RefPtrWillBeRawPtr<Document> document = Document::create(); | |
| 199 RefPtrWillBeRawPtr<Element> element = SVGSetElement::create(*document); | |
| 200 element->stripScriptingAttributes(attributes); | |
| 201 | |
| 202 EXPECT_EQ(0ul, attributes.size()) << | |
| 203 "stripScriptingAttributes should strip an animation 'to' attribute " | |
| 204 "with a JavaScript URL value."; | |
| 205 } | |
| 206 | |
| 207 TEST( | |
| 208 UnsafeSVGAttributeSanitizationTest, | |
| 209 stripScriptingAttributes_stripsAnimationsThatSetJavascriptURLs_values) | |
| 210 { | |
| 211 Vector<Attribute> attributes; | |
| 212 attributes.append( | |
| 213 Attribute(SVGNames::valuesAttr, "evil; javascript:confirm()")); | |
| 214 | |
| 215 RefPtrWillBeRawPtr<Document> document = Document::create(); | |
| 216 RefPtrWillBeRawPtr<Element> element = SVGAnimateElement::create(*document); | |
| 217 element = SVGAnimateElement::create(*document); | |
| 218 element->stripScriptingAttributes(attributes); | |
| 219 | |
| 220 EXPECT_EQ(0ul, attributes.size()) << | |
| 221 "stripScriptingAttributes should strip an animation 'values' attribute " | |
| 222 "which contains a JavaScript URL value."; | |
| 223 } | |
| 224 | |
| 225 TEST( | |
| 226 UnsafeSVGAttributeSanitizationTest, | |
| 227 stripScriptingAttributes_doesNotStripInnocuousAnimationAttributes) | |
| 228 { | |
| 229 Vector<Attribute> attributes; | |
| 230 attributes.append(Attribute(SVGNames::fromAttr, "hello, world!")); | |
| 231 | |
| 232 RefPtrWillBeRawPtr<Document> document = Document::create(); | |
| 233 RefPtrWillBeRawPtr<Element> element = SVGSetElement::create(*document); | |
| 234 element->stripScriptingAttributes(attributes); | |
| 235 | |
| 236 EXPECT_EQ(1ul, attributes.size()) << | |
| 237 "stripScriptingAttributes should not strip an animation 'from' " | |
| 238 "attribute with a non-JavaScript URL value."; | |
| 239 } | |
| 240 | |
| 241 TEST( | |
| 242 UnsafeSVGAttributeSanitizationTest, | |
| 243 stripScriptingAttributes_doesNotStripAnimationAttributesInOtherContexts) | |
| 244 { | |
| 245 Vector<Attribute> attributes; | |
| 246 attributes.append(Attribute(SVGNames::fromAttr, "javascript:alert()")); | |
| 247 | |
| 248 RefPtrWillBeRawPtr<Document> document = Document::create(); | |
| 249 RefPtrWillBeRawPtr<Element> element = SVGDiscardElement::create(*document); | |
| 250 element->stripScriptingAttributes(attributes); | |
| 251 | |
| 252 EXPECT_EQ(1ul, attributes.size()) << | |
| 253 "stripScriptingAttributes should not strip a 'from' attribute used on " | |
| 254 "a non-animation element."; | |
| 255 } | |
| 256 | |
| 257 } // namespace blink | |
| OLD | NEW |