whatwg / html

HTML Standard
https://html.spec.whatwg.org/multipage/
Other
8.16k stars 2.68k forks source link

The DataTransfer API should be safer #1244

Open hallvors opened 8 years ago

hallvors commented 8 years ago

Using the DataTransfer API you can make data travel across security boundaries - web to local application. This can enable malicious payloads - for example malformed data intended to exploit bugs in data processing of local applications that are targets of Drag-and-drop or copy/paste operations.

For better or worse, we have to consider these issues. Implementations are already adding security precautions that are not covered by the current spec, such as

The algorithms in the spec need to add such measures for security reasons.

hallvors commented 8 years ago

My current thinking is that we should add another drag data store mode called for example safe read/write or filtered read/write. This is the default mode for JS without special permissions and privileges, and it works like this:

domenic commented 8 years ago

Thanks for raising this! I'm just digging into this part of the spec for the first time, so please let me know if I'm misunderstanding the current spec or your suggestion.

First let me make sure I am understanding the exact concern, since there is a lot of surface area on the API. I think this is about using dataTransfer.setData(imgMimeType, maliciousString), or dataTransfer.items.add(maliciousString, imgMimeType), or dataTransfer.items.add(maliciousFile). Here maliciousString and maliciousFile are meant to trigger bad paths in image-decoding algorithms. Is this the API surface we're worried about? I'll proceed assuming so, but let me know if I missed something.

One question I had is what happens when I try to read back that data for your transformable types, via the getData or items[i] APIs. Does the browser give me back the transformed data, with a new type string (e.g. all images become "image/png")? Or does it store the original data alongside the transformed data (or maybe do just-in-time transformation only for outside-the-browser drop targets)? Figuring this out seems important because it changes how much of the resulting spec text is about observable differences, versus about unobservable-from-the-web advice to implementations that they should consider transforming certain formats before exposing them to native code.

Another minor question is what the motivation is for read/write mode + safe read/write mode. Shouldn't we just change read/write mode to always be safe?

Any custom data types (including files/blobs/whatever) is serialized into a simple format and written to the clipboard as a blob described as application/x-web-browser-customdata (does such a type make sense?)

Could you give a bit more detail here?

If I understand, the overall desire here is to avoid giving apps the ability to arbitrarily set binary data + a type string on the system clipboard, because later, the user might paste it into an app that tries to decode it using native decoders, and trigger an exploit. That makes sense. So we have a safelist of always-safe types, and another list of can-be-made-safe types, and no other type strings can be set on the clipboard besides those.

But then we still want to allow applications to put arbitrary data on the clipboard, even if the app doesn't get to specify the type? In that case I might go for censoring all provided types that fall outside the safe lists to application/octet-stream. Again I have the question of whether this is observable by using dataTransfer.items[0].type, or whether this is just advice to the browser on how to use the OS's clipboard APIs.

hallvors commented 8 years ago

@domenic good questions. Firstly: yes, your understanding of the concerns is pretty accurate. Some extra details are better explained privately (apologies). If possible, I think just-in-time transforms would be better (so when data is written to the clipboard/dropped).

Applications (Chrome in production, Firefox about to ship) already do the "custom types in proprietary format" thing. It's used internally by the browser to handle copying between tabs where scripts write/read custom types (a high profile example is Google Docs).

Admittedly, this is somewhat self-contradicting. Firstly, we want to hamper web->native data transfer for security reasons and won't allow scripts to write application/x-vendor-fancy-data for the native fancy-data app to pick up. On second thought, we'll allow that anyway but put it in a custom field so the native fancy-data app if it really wants to can read the application/x-web-browser-custom-data, parse it and extract the application/x-vendor-fancy-data stuff anyway. My thinking is that interoperability is important and we wanted to enable for example copying from G Docs in Chrome to G Docs in Firefox and vice versa - but I admit this is a corner case..

domenic commented 8 years ago

If possible, I think just-in-time transforms would be better (so when data is written to the clipboard/dropped).

OK, great. So if I do dataTransfer.setData(imgMimeType, maliciousString), and then do dataTransfer.getData(imgMimeType), I'll still get back maliciousString---it won't be censored or transcoded? And if I do .items[0].type, it will give back imgMimeType, not "image/png" always?

If that's the case, this should be a fairly straightforward spec change, as it's about adding advice for implementations that they should not allow user-provided data to make its way onto the clipboard or into other applications directly, and should consider transcoding it or at least censoring its type string. But it won't change the normative processing model of how to store types, and won't require a new drag store mode.

How does that sound to you?

Applications (Chrome in production, Firefox about to ship) already do the "custom types in proprietary format" thing. It's used internally by the browser to handle copying between tabs where scripts write/read custom types (a high profile example is Google Docs).

I'm not quite sure I understand this part. Is this saying that when we add the above advice, we should advise that the type string that other applications see is application/x-web-browser-custom-data? And Chrome and Firefox are shipping/going to ship that string?

hallvors commented 8 years ago

@domenic my remaining question is if we're going to want an "unfiltered" mode. I.e. should we cater for the possibility that browser vendors might implement a "wash my hands" permission and let users say "this app/site is really, really trusted, let it write custom data formats for native apps like Photoshop/*Office/whatever without further ado"? We have had (and will continue to have) demand from authors for such full access... It's hard to imagine a useful UI though.

If we want to leave the door open to permit "full access", I think "modes" is the best way to do it.

Regarding the custom types: obviously, if we want to enable interoperability between the same web apps running in different browser engines, we need to spec a shared clipboard format for custom data. This implies that other native software will also see a "Web browser custom data" clipboard entry (by any description after some bikeshedding) and potentially grow features that start making use of said "Web browser custom data" on paste/drop.

If this is considered an extremely rare use case we should not cater for, and custom data on the real OS clipboard is considered too risky, we can of course spec that the browsers should keep custom data somewhere internally and augment the DataTransfer object with the internally stored custom data as if it were on the clipboard on the next paste (unless the OS clipboard's contents changed meanwhile). This seems harder to test and harder to get right, but it is a judgement call.

domenic commented 8 years ago

@hallvors would you mind answering my questions from above? They were:

So if I do dataTransfer.setData(imgMimeType, maliciousString), and then do dataTransfer.getData(imgMimeType), I'll still get back maliciousString---it won't be censored or transcoded? And if I do .items[0].type, it will give back imgMimeType, not "image/png" always?

and also

Is this saying that when we add the above advice, we should advise that the type string that other applications see is application/x-web-browser-custom-data? And Chrome and Firefox are shipping/going to ship that string?

Regarding unfiltered mode:

my remaining question is if we're going to want an "unfiltered" mode. I.e. should we cater for the possibility that browser vendors might implement a "wash my hands" permission and let users say "this app/site is really, really trusted, let it write custom data formats for native apps like Photoshop/*Office/whatever without further ado"? We have had (and will continue to have) demand from authors for such full access... It's hard to imagine a useful UI though.

I think we should consider adding that if 2+ browsers actually have plans to ship it. Otherwise, there's no need to complicate the spec for a hypothetical feature.

Regarding the custom types: obviously, if we want to enable interoperability between the same web apps running in different browser engines, we need to spec a shared clipboard format for custom data.

This does sound like an interesting project. Is there multi-vendor interest in creating such a spec and implementing it?