Changeset 253486 in webkit


Ignore:
Timestamp:
Dec 13, 2019 10:39:40 AM (4 years ago)
Author:
Wenson Hsieh
Message:

[Clipboard API] Sanitize HTML and image data written using clipboard.write
https://bugs.webkit.org/show_bug.cgi?id=205188
<rdar://problem/57612968>

Reviewed by Darin Adler.

Source/WebCore:

Sanitizes HTML ("text/html") and image ("image/png") content when writing to the platform pasteboard using the
clipboard API. See below for more details.

Tests: editing/async-clipboard/sanitize-when-reading-markup.html

editing/async-clipboard/sanitize-when-writing-image.html
ClipboardTests.WriteSanitizedMarkup

  • Modules/async-clipboard/ClipboardItemBindingsDataSource.cpp:

(WebCore::ClipboardItemBindingsDataSource::ClipboardItemTypeLoader::sanitizeDataIfNeeded):

Add a new helper method to sanitize m_data after loading finishes, but before invoking the completion handler
to notify the data source about the clipboard data. Currently, we support writing "text/plain", "text/uri-list",
"text/html" and "image/png"; we sanitize HTML by stripping away hidden content such as comments, script, and
event listeners, and sanitize image data by painting it into a new graphics context and re-encoding the rendered
contents as an image.

(WebCore::ClipboardItemBindingsDataSource::ClipboardItemTypeLoader::invokeCompletionHandler):

  • Modules/async-clipboard/ClipboardItemBindingsDataSource.h:
  • platform/PlatformPasteboard.h:
  • platform/cocoa/PasteboardCocoa.mm:

(WebCore::cocoaTypeToImageType):

  • platform/ios/PlatformPasteboardIOS.mm:

(WebCore::PlatformPasteboard::platformPasteboardTypeForSafeTypeForDOMToReadAndWrite):

Adjust these helpers to map "image/png" to the platform PNG type on iOS ("public.png"). The extra
IncludeImageTypes argument was added to avoid considering "image/png" a web-safe type for writing and reading
when exercising DataTransfer APIs, which currently don't support reading the "image/png" MIME type. In the
future, we should consider adding support for image sanitization when using DataTransfer.setData or
DataTransferItemList.add, and then remove this flag.

(WebCore::createItemProviderRegistrationList):

  • platform/mac/LegacyNSPasteboardTypes.h:

Add an entry for legacyPNGPasteboardType on macOS, and replace one use of it in PasteboardCocoa.mm.

(WebCore::legacyPNGPasteboardType):

  • platform/mac/PlatformPasteboardMac.mm:

(WebCore::PlatformPasteboard::write):
(WebCore::PlatformPasteboard::platformPasteboardTypeForSafeTypeForDOMToReadAndWrite):

Likewise, map "image/png" to legacyPNGPasteboardType() on macOS, which was added above.

(WebCore::createPasteboardItem):

Tools:

Adds an API test to verify that the markup written to the platform pasteboard on macOS and iOS is sanitized, and
does not contain hidden content, such as script elements.

  • TestWebKitAPI/Tests/WebKitCocoa/ClipboardTests.mm:

(-[TestWKWebView writeString:toClipboardWithType:]):
(readMarkupFromPasteboard):

  • TestWebKitAPI/Tests/WebKitCocoa/clipboard.html:

LayoutTests:

  • editing/async-clipboard/sanitize-when-reading-markup-expected.txt: Added.
  • editing/async-clipboard/sanitize-when-reading-markup.html: Added.

Add a test to verify that markup is sanitized when copying and pasting across different security origins.

  • editing/async-clipboard/sanitize-when-writing-image-expected.txt: Added.
  • editing/async-clipboard/sanitize-when-writing-image.html: Added.

Add a test to verify that "image/png" data is sanitized, and one or more written image data that cannot be
decoded results in the promise being rejected.

  • platform/mac-wk1/TestExpectations:
  • platform/win/TestExpectations:
Location:
trunk
Files:
4 added
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r253483 r253486  
     12019-12-13  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        [Clipboard API] Sanitize HTML and image data written using clipboard.write
     4        https://bugs.webkit.org/show_bug.cgi?id=205188
     5        <rdar://problem/57612968>
     6
     7        Reviewed by Darin Adler.
     8
     9        * editing/async-clipboard/sanitize-when-reading-markup-expected.txt: Added.
     10        * editing/async-clipboard/sanitize-when-reading-markup.html: Added.
     11
     12        Add a test to verify that markup is sanitized when copying and pasting across different security origins.
     13
     14        * editing/async-clipboard/sanitize-when-writing-image-expected.txt: Added.
     15        * editing/async-clipboard/sanitize-when-writing-image.html: Added.
     16
     17        Add a test to verify that "image/png" data is sanitized, and one or more written image data that cannot be
     18        decoded results in the promise being rejected.
     19
     20        * platform/mac-wk1/TestExpectations:
     21        * platform/win/TestExpectations:
     22
    1232019-12-13  Chris Dumez  <cdumez@apple.com>
    224
  • trunk/LayoutTests/platform/mac-wk1/TestExpectations

    r253434 r253486  
    7373editing/async-clipboard/clipboard-read-text-from-platform.html [ Skip ]
    7474editing/async-clipboard/clipboard-read-text-same-origin.html [ Skip ]
     75editing/async-clipboard/sanitize-when-reading-markup.html [ Skip ]
    7576
    7677imported/w3c/web-platform-tests/websockets/Close-1000-reason.any.html [ Pass Failure ]
  • trunk/LayoutTests/platform/win/TestExpectations

    r253239 r253486  
    12011201webkit.org/b/203100 editing/async-clipboard/clipboard-read-text-same-origin.html [ Skip ]
    12021202webkit.org/b/203100 editing/async-clipboard/clipboard-read-text.html [ Skip ]
     1203webkit.org/b/203100 editing/async-clipboard/sanitize-when-writing-image.html [ Skip ]
     1204webkit.org/b/203100 editing/async-clipboard/sanitize-when-reading-markup.html [ Skip ]
    12031205
    12041206webkit.org/b/140783 [ Release ] editing/pasteboard/copy-standalone-image.html [ Failure ImageOnlyFailure ]
  • trunk/Source/WebCore/ChangeLog

    r253483 r253486  
     12019-12-13  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        [Clipboard API] Sanitize HTML and image data written using clipboard.write
     4        https://bugs.webkit.org/show_bug.cgi?id=205188
     5        <rdar://problem/57612968>
     6
     7        Reviewed by Darin Adler.
     8
     9        Sanitizes HTML ("text/html") and image ("image/png") content when writing to the platform pasteboard using the
     10        clipboard API. See below for more details.
     11
     12        Tests: editing/async-clipboard/sanitize-when-reading-markup.html
     13               editing/async-clipboard/sanitize-when-writing-image.html
     14               ClipboardTests.WriteSanitizedMarkup
     15
     16        * Modules/async-clipboard/ClipboardItemBindingsDataSource.cpp:
     17        (WebCore::ClipboardItemBindingsDataSource::ClipboardItemTypeLoader::sanitizeDataIfNeeded):
     18
     19        Add a new helper method to sanitize `m_data` after loading finishes, but before invoking the completion handler
     20        to notify the data source about the clipboard data. Currently, we support writing "text/plain", "text/uri-list",
     21        "text/html" and "image/png"; we sanitize HTML by stripping away hidden content such as comments, script, and
     22        event listeners, and sanitize image data by painting it into a new graphics context and re-encoding the rendered
     23        contents as an image.
     24
     25        (WebCore::ClipboardItemBindingsDataSource::ClipboardItemTypeLoader::invokeCompletionHandler):
     26        * Modules/async-clipboard/ClipboardItemBindingsDataSource.h:
     27        * platform/PlatformPasteboard.h:
     28        * platform/cocoa/PasteboardCocoa.mm:
     29        (WebCore::cocoaTypeToImageType):
     30        * platform/ios/PlatformPasteboardIOS.mm:
     31        (WebCore::PlatformPasteboard::platformPasteboardTypeForSafeTypeForDOMToReadAndWrite):
     32
     33        Adjust these helpers to map "image/png" to the platform PNG type on iOS ("public.png"). The extra
     34        IncludeImageTypes argument was added to avoid considering "image/png" a web-safe type for writing and reading
     35        when exercising DataTransfer APIs, which currently don't support reading the "image/png" MIME type. In the
     36        future, we should consider adding support for image sanitization when using DataTransfer.setData or
     37        DataTransferItemList.add, and then remove this flag.
     38
     39        (WebCore::createItemProviderRegistrationList):
     40        * platform/mac/LegacyNSPasteboardTypes.h:
     41
     42        Add an entry for legacyPNGPasteboardType on macOS, and replace one use of it in PasteboardCocoa.mm.
     43
     44        (WebCore::legacyPNGPasteboardType):
     45        * platform/mac/PlatformPasteboardMac.mm:
     46        (WebCore::PlatformPasteboard::write):
     47        (WebCore::PlatformPasteboard::platformPasteboardTypeForSafeTypeForDOMToReadAndWrite):
     48
     49        Likewise, map "image/png" to legacyPNGPasteboardType() on macOS, which was added above.
     50
     51        (WebCore::createPasteboardItem):
     52
    1532019-12-13  Chris Dumez  <cdumez@apple.com>
    254
  • trunk/Source/WebCore/Modules/async-clipboard/ClipboardItemBindingsDataSource.cpp

    r252658 r253486  
    2727#include "ClipboardItemBindingsDataSource.h"
    2828
     29#include "BitmapImage.h"
    2930#include "Blob.h"
    3031#include "Clipboard.h"
     
    3334#include "FileReaderLoader.h"
    3435#include "Frame.h"
     36#include "GraphicsContext.h"
     37#include "ImageBuffer.h"
    3538#include "JSBlob.h"
    3639#include "JSDOMPromise.h"
     
    253256}
    254257
     258void ClipboardItemBindingsDataSource::ClipboardItemTypeLoader::sanitizeDataIfNeeded()
     259{
     260    if (m_type == "text/html"_s) {
     261        String markupToSanitize;
     262        if (WTF::holds_alternative<Ref<SharedBuffer>>(m_data)) {
     263            auto& buffer = WTF::get<Ref<SharedBuffer>>(m_data);
     264            markupToSanitize = String::fromUTF8(buffer->data(), buffer->size());
     265        } else if (WTF::holds_alternative<String>(m_data))
     266            markupToSanitize = WTF::get<String>(m_data);
     267
     268        if (markupToSanitize.isEmpty())
     269            return;
     270
     271        m_data = { sanitizeMarkup(markupToSanitize) };
     272    }
     273
     274    if (m_type == "image/png"_s) {
     275        RefPtr<SharedBuffer> bufferToSanitize;
     276        if (WTF::holds_alternative<Ref<SharedBuffer>>(m_data))
     277            bufferToSanitize = WTF::get<Ref<SharedBuffer>>(m_data).ptr();
     278        else if (WTF::holds_alternative<String>(m_data))
     279            bufferToSanitize = utf8Buffer(WTF::get<String>(m_data));
     280
     281        if (!bufferToSanitize || bufferToSanitize->isEmpty())
     282            return;
     283
     284        auto bitmapImage = BitmapImage::create();
     285        bitmapImage->setData(WTFMove(bufferToSanitize), true);
     286        auto imageBuffer = ImageBuffer::create(bitmapImage->size(), Unaccelerated);
     287        if (!imageBuffer) {
     288            m_data = { nullString() };
     289            return;
     290        }
     291
     292        imageBuffer->context().drawImage(bitmapImage.get(), FloatPoint::zero());
     293        m_data = { SharedBuffer::create(imageBuffer->toData("image/png"_s)) };
     294    }
     295}
     296
    255297void ClipboardItemBindingsDataSource::ClipboardItemTypeLoader::invokeCompletionHandler()
    256298{
    257     if (auto completion = WTFMove(m_completionHandler))
     299    if (auto completion = WTFMove(m_completionHandler)) {
     300        sanitizeDataIfNeeded();
    258301        completion();
     302    }
    259303}
    260304
  • trunk/Source/WebCore/Modules/async-clipboard/ClipboardItemBindingsDataSource.h

    r252658 r253486  
    7474        ClipboardItemTypeLoader(const String& type, CompletionHandler<void()>&&);
    7575
     76        void sanitizeDataIfNeeded();
    7677        void invokeCompletionHandler();
    7778
  • trunk/Source/WebCore/platform/PlatformPasteboard.h

    r251421 r253486  
    6767    WEBCORE_EXPORT static String uniqueName();
    6868
    69     WEBCORE_EXPORT static String platformPasteboardTypeForSafeTypeForDOMToReadAndWrite(const String& domType);
     69    enum class IncludeImageTypes : bool { No, Yes };
     70    static String platformPasteboardTypeForSafeTypeForDOMToReadAndWrite(const String& domType, IncludeImageTypes = IncludeImageTypes::No);
    7071
    7172    WEBCORE_EXPORT void getTypes(Vector<String>& types);
  • trunk/Source/WebCore/platform/cocoa/PasteboardCocoa.mm

    r251421 r253486  
    6969        return ImageType::TIFF;
    7070#if PLATFORM(MAC)
    71     if (cocoaType == "Apple PNG pasteboard type") // NSPNGPboardType
     71    if (cocoaType == String(legacyPNGPasteboardType())) // NSPNGPboardType
    7272        return ImageType::PNG;
    7373#endif
  • trunk/Source/WebCore/platform/ios/PlatformPasteboardIOS.mm

    r252450 r253486  
    323323}
    324324
    325 String PlatformPasteboard::platformPasteboardTypeForSafeTypeForDOMToReadAndWrite(const String& domType)
     325String PlatformPasteboard::platformPasteboardTypeForSafeTypeForDOMToReadAndWrite(const String& domType, IncludeImageTypes includeImageTypes)
    326326{
    327327    if (domType == "text/plain")
     
    333333    if (domType == "text/uri-list")
    334334        return kUTTypeURL;
     335
     336    if (includeImageTypes == IncludeImageTypes::Yes && domType == "image/png")
     337        return kUTTypePNG;
    335338
    336339    return { };
     
    604607
    605608        NSString *stringValue = value;
    606         auto cocoaType = PlatformPasteboard::platformPasteboardTypeForSafeTypeForDOMToReadAndWrite(type).createCFString();
     609        auto cocoaType = PlatformPasteboard::platformPasteboardTypeForSafeTypeForDOMToReadAndWrite(type, PlatformPasteboard::IncludeImageTypes::Yes).createCFString();
    607610        if (UTTypeConformsTo(cocoaType.get(), kUTTypeURL))
    608611            [representationsToRegister addRepresentingObject:[NSURL URLWithString:stringValue]];
  • trunk/Source/WebCore/platform/mac/LegacyNSPasteboardTypes.h

    r235935 r253486  
    8787}
    8888
     89inline NSString *legacyPNGPasteboardType()
     90{
     91    return @"Apple PNG pasteboard type";
     92}
     93
    8994} // namespace WebCore
    9095
  • trunk/Source/WebCore/platform/mac/PlatformPasteboardMac.mm

    r252627 r253486  
    227227    NSMutableArray *types = [NSMutableArray array];
    228228    data.forEachType([&] (auto& type) {
    229         NSString *platformType = platformPasteboardTypeForSafeTypeForDOMToReadAndWrite(type);
     229        NSString *platformType = platformPasteboardTypeForSafeTypeForDOMToReadAndWrite(type, IncludeImageTypes::Yes);
    230230        if (platformType.length)
    231231            [types addObject:platformType];
     
    238238    [m_pasteboard declareTypes:types owner:nil];
    239239
    240     data.forEachPlatformString([&] (auto& type, auto& data) {
    241         auto platformType = platformPasteboardTypeForSafeTypeForDOMToReadAndWrite(type);
    242         ASSERT(!platformType.isEmpty());
    243         if (!platformType.isEmpty())
    244             [m_pasteboard setString:data forType:platformType];
     240    data.forEachPlatformStringOrBuffer([&] (auto& type, auto& stringOrBuffer) {
     241        auto platformType = platformPasteboardTypeForSafeTypeForDOMToReadAndWrite(type, IncludeImageTypes::Yes);
     242        if (platformType.isEmpty())
     243            return;
     244
     245        if (WTF::holds_alternative<Ref<SharedBuffer>>(stringOrBuffer)) {
     246            if (auto platformData = WTF::get<Ref<SharedBuffer>>(stringOrBuffer)->createNSData())
     247                [m_pasteboard setData:platformData.get() forType:platformType];
     248        } else if (WTF::holds_alternative<String>(stringOrBuffer)) {
     249            auto string = WTF::get<String>(stringOrBuffer);
     250            if (!!string)
     251                [m_pasteboard setString:string forType:platformType];
     252        }
    245253    });
    246254
     
    258266}
    259267
    260 String PlatformPasteboard::platformPasteboardTypeForSafeTypeForDOMToReadAndWrite(const String& domType)
     268String PlatformPasteboard::platformPasteboardTypeForSafeTypeForDOMToReadAndWrite(const String& domType, IncludeImageTypes includeImageTypes)
    261269{
    262270    if (domType == "text/plain")
     
    268276    if (domType == "text/uri-list")
    269277        return legacyURLPasteboardType();
     278
     279    if (includeImageTypes == IncludeImageTypes::Yes && domType == "image/png")
     280        return legacyPNGPasteboardType();
    270281
    271282    return { };
     
    475486            return;
    476487
    477         if (WTF::holds_alternative<String>(stringOrBuffer)) {
    478             [item setString:WTF::get<String>(stringOrBuffer) forType:platformType];
    479             return;
    480         }
    481 
    482488        if (WTF::holds_alternative<Ref<SharedBuffer>>(stringOrBuffer)) {
    483489            if (auto platformData = WTF::get<Ref<SharedBuffer>>(stringOrBuffer)->createNSData())
    484490                [item setData:platformData.get() forType:platformType];
     491        } else if (WTF::holds_alternative<String>(stringOrBuffer)) {
     492            auto string = WTF::get<String>(stringOrBuffer);
     493            if (!!string)
     494                [item setString:string forType:platformType];
    485495        }
    486496    });
  • trunk/Tools/ChangeLog

    r253484 r253486  
     12019-12-13  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        [Clipboard API] Sanitize HTML and image data written using clipboard.write
     4        https://bugs.webkit.org/show_bug.cgi?id=205188
     5        <rdar://problem/57612968>
     6
     7        Reviewed by Darin Adler.
     8
     9        Adds an API test to verify that the markup written to the platform pasteboard on macOS and iOS is sanitized, and
     10        does not contain hidden content, such as script elements.
     11
     12        * TestWebKitAPI/Tests/WebKitCocoa/ClipboardTests.mm:
     13        (-[TestWKWebView writeString:toClipboardWithType:]):
     14        (readMarkupFromPasteboard):
     15        * TestWebKitAPI/Tests/WebKitCocoa/clipboard.html:
     16
    1172019-12-13  Kate Cheney  <katherine_cheney@apple.com>
    218
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ClipboardTests.mm

    r251479 r253486  
    3030#import "UIKitSPI.h"
    3131#import <CoreServices/CoreServices.h>
     32#import <WebCore/LegacyNSPasteboardTypes.h>
    3233#import <WebKit/WKPreferencesPrivate.h>
    3334#import <WebKit/_WKExperimentalFeature.h>
     
    4849    }];
    4950    [self evaluateJavaScript:@"readClipboard()" completionHandler:nil];
     51    TestWebKitAPI::Util::run(&done);
     52}
     53
     54- (void)writeString:(NSString *)string toClipboardWithType:(NSString *)type
     55{
     56    __block bool done = false;
     57    [self performAfterReceivingMessage:@"wroteStringToClipboard" action:^{
     58        done = true;
     59    }];
     60    [self evaluateJavaScript:[NSString stringWithFormat:@"writeStringToClipboard(`%@`, `%@`)", type, string] completionHandler:nil];
    5061    TestWebKitAPI::Util::run(&done);
    5162}
     
    119130}
    120131
     132static NSString *readMarkupFromPasteboard()
     133{
     134#if PLATFORM(MAC)
     135    NSData *rawData = [NSPasteboard.generalPasteboard dataForType:WebCore::legacyHTMLPasteboardType()];
     136#elif PLATFORM(IOS)
     137    NSData *rawData = [UIPasteboard.generalPasteboard dataForPasteboardType:(__bridge NSString *)kUTTypeHTML];
     138#endif
     139    return [[[NSString alloc] initWithData:rawData encoding:NSUTF8StringEncoding] autorelease];
     140}
     141
    121142TEST(ClipboardTests, ReadMultipleItems)
    122143{
     
    134155    EXPECT_WK_STREQ("https://webkit.org/", [webView stringByEvaluatingJavaScript:@"clipboardData[3]['text/html'].querySelector('a').href"]);
    135156}
     157
     158TEST(ClipboardTests, WriteSanitizedMarkup)
     159{
     160    auto webView = createWebViewForClipboardTests();
     161    [webView writeString:@"<script>/* super secret */</script>This is a test." toClipboardWithType:@"text/html"];
     162
     163    NSString *writtenMarkup = readMarkupFromPasteboard();
     164    EXPECT_TRUE([writtenMarkup containsString:@"This is a test."]);
     165    EXPECT_FALSE([writtenMarkup containsString:@"super secret"]);
     166    EXPECT_FALSE([writtenMarkup containsString:@"<script>"]);
     167}
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/clipboard.html

    r251377 r253486  
    2929exception = null;
    3030
     31async function writeStringToClipboard(type, string) {
     32    try {
     33        const itemData = {};
     34        itemData[type] = string;
     35        await navigator.clipboard.write([new ClipboardItem(itemData)]);
     36    } catch (e) {
     37        exception = e;
     38    } finally {
     39        webkit.messageHandlers.testHandler.postMessage("wroteStringToClipboard");
     40    }
     41}
     42
    3143async function readClipboard() {
    3244    try {
Note: See TracChangeset for help on using the changeset viewer.