[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Public WebGL] Proposed change to WebGL spec section 4.2 (Security Origin Restrictions)

On Mon, Oct 4, 2010 at 3:44 PM, Chris Marrin <cmarrin@apple.com> wrote:

On Oct 4, 2010, at 2:23 PM, Brian Cornell wrote:

> Currently section 4.2 of the specification provides a sufficient but not necessary restriction on readPixels to prevent reading data from other origins. Greater functionality could be given to application developers by slightly increasing the complexity here, while still maintaining the desired security.
> I propose that rather than texImage2D from a different origin or unclean resource causing the canvas to be marked as unclean, it would set a flag marking that texture as unclean, and also set a flag marking the current framebuffer as unclean. Binding a texture would set the flag marking the framebuffer as unclean if the bound texture is marked as unclean. Changing the attached framebuffer would set the flag marking the new framebuffer as unclean if any bound texture is marked as unclean. The origin-clean flag of the canvas would reflect the status of the currently bound framebuffer.
> This would allow developers to read the contents of a framebuffer from a context where different origin images were used, but only in certain same circumstances, such as the following pseudocode:
> create texture A
> bind texture A
> texImage2D into A with different origin data // canvas, default framebuffer, and texture are all now unclean
> draw some stuff using texture A and cached buffers
> bind null in place of texture A // canvas and default framebuffer are still marked as unclean
> create framebuffer B // framebuffer B is clean
> bind framebuffer B // canvas and framebuffer B are marked as clean
> draw some stuff using same cached buffers but not texture A
> readPixels // this can now succeed because the unclean data has never been connected to framebuffer B
> bind default framebuffer // canvas now back to unclean because default framebuffer is unclean
> bind texture A
> draw
> ...
> This is a significant win over using separate canvases for the two operations if the unclean drawing and the clean drawing share a significant amount of buffered data or clean textures.
> As an example of how this could be used, say you had a 3d game that showed ads on billboards in the game. The ads are served as images by some other domain. You want to include a way to take screenshots in the game. For a screenshot, you use a different framebuffer and don't bind the images for ads, you render a black box or an ad placeholder image from the clean origin instead. You want to reuse all of the buffered data and clean textures for the screenshot, so using a different canvas would be painful and slow. Using this proposed change you would be able to read the pixels from the alternate framebuffer as long as no ad textures were ever bound at the same time as that framebuffer.
> Thoughts?

This seems like enough added complexity that it will be hard to maintain security. There are many places where a hole might be discovered to give an author access to the other's origin's pixels. Seems like it would be easier if, in your use case, you simply created a new canvas, initialized it and loaded it with resources, skipping the undesired textures. That keeps things clean and lets you get your screen shot. That's more work and more resource allocation, but keeps the system simple and easier to keep secure.

It would be rather complex. Here's the list off the top of my head

It seems like the rules you'd want are

*) A texture level is marked as "tainted" if an non origin clean image/canvas/texture/video is loaded into it with texImage2D or texSubImage2D
*) A texture level is marked as "clean" if a origin clean image/canvas/texture/video/arraybuffer is loaded into it only with texImage2d 
*) All of a texture's levels are marked as "tainted" if generateMipmap is called and level 0 is tainted.
*) All of a texture's levels are marked as "clean" if generateMipmap is called and level 0 is "clean"
*) If any level in a texture is marked as "tainted" the texture is considered "tainted"
*) When rendering, if an texture used in rendering is marked as tainted then:
  *) if rendering to the backbuffer the backbuffer is marked as tainted
  *) if rendering to a framebuffer, all of its renderbuffers and textures levels are marked as tainted. 
*) If clear is called and the color mask is true, true, true, true (and if there is a depth buffer, the depth mask is true, and if there is a stencil the stencil mask is -1) and if scissor is disabled then:
  *) if rendering to the backbuffer the backbuffer is marked as clean
  *) if rendering to a framebuffer, all of its renderbuffers and textures levels are marked as clean. 
*) A framebuffer is considered tainted if any of it's current renderbuffers or texture levels are tainted
*) If the current rendering target (framebuffer or backbuffer) is marked as tainted then:
  *) calling readPixels will throw SECURITY_ERR
  *) calling copyTexImage or copyTexImag2d will taint the level of the texture being targeted
*) If the current backbuffer is marked as tainted then:
  *) toDataURL will throw SECURITY_ERR
  *) drawImage will mark canvases as non-origin clean

It does seem like quite a PITA though not that hard. I guess the question is is it worth it. It is a common technique to draw using IDs instead of colors and then using readpixels to find out which thing you clicked on. As it is, that technique will only work if you're serving all the assets. Up till now that was probably the most common case but adding 3D to the web might make a cross origin case more common. Does CORS like stuff apply to images so a server can declare images from it are usable by any domain? 



You are currently subscribed to public_webgl@khronos.org.
To unsubscribe, send an email to majordomo@khronos.org with
the following command in the body of your email: