Tuesday, December 27, 2011

Protecting WebGL content (and why you probably shouldn't)

I received an email this morning from a developer that is in a predicament that I think many WebGL developers will find themselves in pretty soon:
Do you have any experience with protecting assets in WebGL? I wrote a quick solution to protect textures during transfer - base64 encoding + concat server side and splitting + creating imgs client side. Still, using WebGL Inspector I can get all textures transferred to the graphics card. I wonder if you have any ideas on how to prevent that. I don't mind open sourcing my apps, but my clients apparently do :)
Ah, that last line is really the crux of the matter, isn't it? Most developers I know don't mind sharing their creations with the world at large, as we tend to understand that there's rarely anything sacred and secret in the lines of code we crank out, but that's not always an easy thing to convince management of. So: What's an enterprising WebGL developer to do when the boss decrees from on high "Protect our content?"

There's a couple ways to approach such a request, in my opinion. First: Do whatever you can to convince said management that you don't need to protect said content. Second: Convince them harder. Third: If all else fails, obscure the content as much as possible. I'll be talking about both approaches in todays post.

Why your content doesn't need protecting, and why it benefits you to leave it open!

You probably don't need to protect your content in the first place. I know that many people's knee-jerk reaction to that statement will probably be: "But you don't understand our situation! Our content is special!" But please, hear me out!

Most of the time when we hear about content protection schemes (DRM), it's in relation to movies and music. There's a good reason for that, too! In those cases the movie or music is the product. But does that really apply to the assets of your WebGL app? What, exactly, is the product that you are trying to provide?

Since the original email was about textures, let's look at those as an example:

This is a wood wall/floor texture from Team Fortress 2. Opinions may differ depending on who you talk to, but in my opinion this is really a work of art. It has an inherent value even as a stand-alone image. Some talented artist put their blood, sweat, and tears into this image. Valve paid for this image to be created. In some way, big or small, the game would be a less polished, less interesting product if not for this image. It is a valuable asset.

So obviously it needs protecting, right?

Well, yes and no.

Problem is that nobody is going to print this image out and hang it on their wall. You're never going to be able to sell high-quality prints of this image. Even though it has a value, for a consumer that value approaches zero pretty quickly unless it is part of a larger product. We value the level that this resource helped create more than the resource itself, and since that level would not be the same without this resource it continues to have value to us as a consumer, but only as part of the larger scene.

So the scene as a whole should be protected, yes?

Maybe, but how much does the consumer really value a static level? People do enjoy being able to simply walk around a scene like that. And in certain industries that may be the product. Autodesk Cloud makes a good case for using resources at this level, and certainly you can imagine that static scenes like this would be valuable for architectural design or similar areas. But how about our TF2 level?

The fact is that, as beautiful as they are, almost nobody would pay to simply walk around a TF2 level. But there are lots and lots of people who will pay very good money to shoot other people while walking around said level. And this is where the actual "product" lies. It's not the assets that people care about, it's the overall experience. The assets are a big part of that experience, true, but only one part of a larger whole. That larger whole also happens to include the multiplayer servers, the achievement systems, the accessory store, the friends list, etc. All things that easily can and should be secured.

The players pay money and in return they download content to their machine, and as such it's easy to mistake the content for the product, but it's not. The ability to play a great game is the product. In other words, Valve is selling the service, not the content. And you should be too!

This is a common theme that you hear from the HTML 5 folks over and over again, and in many cases I fully agree with it. It doesn't always work, but given a bit of thought you'd be surprised at how many scenarios it can be applied to. It all comes down to what you can offer to your customers that can't be replicated on their machine.

The fact is, no matter how hard you try to prevent it the end user will alway be able to scrape out your lovingly built resources and serve them locally if they're really motivated to do so. We don't want to simply roll over and accept piracy as a fact of life, though, so we need to look at what we can provide to complete the overall experience that the users can't simply copy to their hard drive. Multiplayer servers are certainly the obvious choice, but even for single player games or non-gaming apps there's a lot that can be offered server side that lends to the "product". Community features, social network integration, achievements, realtime data feeds, the list goes on! And as web apps, we should be striving to incorporate these connected features from day one. Otherwise, why are you bothering with the web as your platform at all?

Maybe what you're worried about is the sanctity of your artistic vision, though? The author of the email above also mentioned this worry:
Any kid with firebug can download [the textures], draw a penis on my character's face and upload a modified version somewhere.
To which I say: what a wonderful problem to have! If you have a user base that is interested enough in your product to actually start modding it, you've hit a Happy Place™. Certainly nobody looks forward to seeing YouTube videos of their creations running around with crude genitals scribbled on their head, but how much damage is that really doing? One guy modifying his local texture cache won't propagate those changes to anybody else, and if anyone else goes and downloads his changes it's because they want to play as Sir CrotchFace. They get a laugh out of it, everyone else plays on oblivious, and (crucially) they're all using your product! Isn't that the goal in the first place?

It's no mistake that some of the most successful games of all time have been the ones that are easily moddable. Doom, Quake, The Elder Scrolls, Unreal, Half Life, all games that lived on well past their normal life spans because of a thriving mod community. Do you think Minecraft would be nearly as popular as it is now if Mojang had actively been discouraging texture packs and server tweaks? People love to create something that is uniquely theirs, and love to push the boundaries of what any given tech can do. It should be any developers dream to be the target of such affection.

So, long story short: Provide value through your services, not your content, and don't fear the user that wants to tinker. They're often your biggest fans!

Okay, that's great, but my boss doesn't agree. Now what?

So let's give you the benefit of the doubt and say that your content really is honestly and truly so special that it needs to be protected somehow. There are some things you can do to make it more difficult for the other party. Note that I say "more difficult" because the fact is plain and simple that if your content can eventually be displayed on a screen or played on a speaker it CAN be copied. Period. (Big Media is still struggling with this concept, apparently). They best you can do is make it inconvenient enough to discourage casual piracy.

The first way to protect your content is (and I hate to say this) not to use WebGL. Look, let's face it guys, open web standards are designed to distribute content, not hoard it. You're swimming against the current if you want to have open standards and DRM all rolled into a neat package. Content protection is almost inherently proprietary in nature, so your best bet is to go to a plugin framework like Flash, Silverlight, or Unity. These are systems that are designed from the start to distribute content securely, and thus will be much easier to work with if protection is your goal.

If "plugin" is a dirty word for you (or your boss), though, it's also worth looking at Google's Native Client. For those of you that don't know, Native Client (or NaCl, as Google likes to call it) allows you to distribute compiled binaries to users that are then executed in the browser in a sandboxed environment. Because your dealing with native, compiled code there are all sorts of nasty little tricks you can pull off to try and obscure your content from casual browsing. The downside here is that (for now, anyway) NaCl apps will only work in Google's browser. Of course, if you're that concerned about protecting your content requiring a specific browser probably isn't a huge issue.

But... what if you're the type that wants to have their cake and eat it too? You want to embrace the open standards of the web while simultaneously preventing anyone from extracting your precious assets. (You confuse me, I'll ignore that for now.)

First off, you'll want to make all of your code as hard to read as possible. Not the original source files, obviously, but the ones that you put on your public servers. The Closure compiler is great for this, and can actually make your code run faster in some cases! Bonus!

It probably also goes without saying that you'll need to invent your own formats for just about everything. Proprietary mesh and texture formats are always going to be harder to read than a standard COLLADA file and PNG.

Again I'll focus on textures for the moment: You can encrypt your texture all that you want, but at some point you have to unpack it into something that can be displayed on screen, right? The idea is to delay that step as long as possible to avoid having any intermediate tools like Firefox or WebGL Inspector be able to display it normally. To this end, you can get really creative with how you unpack things in your shaders. Ben Adams has a great post about his experiments with manually unpacking compressed textures in a shader that provides some insight into the type of steps that could be taken here. In any case, the idea is to have the fragment shader (which should be distributed obfuscated) do the appropriate math to decrypt/decompress your texture as it's getting written out to screen. Obviously you'll take a performance hit in doing so, but once again I'm guessing that isn't a problem if you are really concerned about protecting your assets.

(You can similarly decrypt vertex buffers in the vertex shader if you're worried about those being lifted, but they tend to be more obscure by nature anyway.)

Another thing to help prevent textures from being easily visible is that you don't have to use HTML images as your texture source. You can send TypedArrays to the GPU directly as your texture source as long as you provide the dimensions and format of your data. I use this to create textures of a flat color all the time:

function createSolidTexture(gl, r, g, b) {
    var data = new Uint8Array([r, g, b]);
    var texture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, 1, 1, 0, gl.RGB, gl.UNSIGNED_BYTE, data);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
    return texture;

This means you can request the texture as an opaque binary through an AJAX call rather than with the Image object, which prevents it from showing up in the Chrome developer tools. (It will still show up in WebGL Inspector, though, so encrypting the texture values is still needed for maximum obscurity.)

Beyond that... well... I think you're out of luck. Certainly there's nothing that I've suggested that prevents someone from tracing through your code, figuring out the algorithms, capturing the data streams, running them through the same decryption process, and reconstructing the original files. But as I said earlier, the idea is to make it inconvenient, not impossible.

But if you've got a user that's really so bound and determined to reverse engineer your entire app just to access the underlying content, I would ask you to think really hard about why you're trying to stop them in the first place.


  1. Nothing you say is actually specific to WebGL. I mean, you could use Stage3D or NaCl or whatever, but at some point your assets are going to be in unencrypted plain view to a simple OpenGL/D3D proxy DLL.

  2. You're absolutely right, though if you went the route of sending encrypted values to the shader there'd at least be a little bit more work to do before they had the right image. The only "upside" to the alternate technologies is that it's not as easy to "view source" and see how everything works. (Though most Flash decompilers will make pretty short work of it!) The idea is to make it more inconvenient for the would-be-pirate, fully knowing that you'll never deter them completely. You can't achieve total protection on even the most locked down of platforms (XBox, iPhone, etc).

    That said, I still think the best route is keeping your content open and your services valuable. Anybody can replicate your assets but they'll never be able to reproduce a thriving community.

  3. Hi Brandon, you make the argument that assets are only part of a larger product and thus are not valuable enough to protect.

    Of course, that is only true for casual users. *They* don't care about that lonely image or source-code.

    But if I were a developer creating a competing game, I could very well benefit from all that lonely images, code and scripts, since I can *combine* it into that larger product that has value. It wouldn't cost me a dime, and instead I could use my money to do advertising or selling the game for cheap and as such build a larger community than the original product ever had.

    For analogy: a free-to-copy-gearbox has no use to the average car-owner, but a garage-owner can built it into any car and benefit enormously.

  4. That's true Willem, but your best recourse is probably legal not technical. Any piece of software can be reverse engineered.

    Also, many of the more artistic resources in a game will be pretty recognizable. For the rest you could probably find free versions online?

    I sometimes think people cling too hard to copyright. If your work benefits someone else that doesn't necessarily disadvantage you. If anything, the networking effect can increase your product's popularity.

  5. @Willem it's about who does the offending (of copyright, yours in that case). It's another company/developer, not thousands, not hundreds, if push comes to shove, maybe more then one.

    And instead of seeing this as offensive, you can just as well see it as a business opportunity. Ask them politely to acquire a license to your content or stop using it. Most developers will comply with that.

  6. I'd like to reiterate Rehno and Florian's points.

    It's really a matter of scale. There are a large number of users that would be happy to use your product for free/illegally if it's made easy for them, but how many developers are out there that are willing to illegally benefit from your IP? The number is probably low enough that, inconvenient as it may be, you can handle them on a legal basis. It's also worth considering that these few highly technical users are going to be the first ones to figure out how to crack you protection schemes, which makes targeting them even more futile.

    Additionally, not every instance of resource reuse will be harmful to you. Allow me to point out that I've been serving people resources from Quake 3 that I have no license to for over a year now. I'm doing so under the premise that my use of the resources is primarily educational, the resources in question are fairly old, I have not replicated the original gameplay or turned it into a different game, and if anything my demo promotes the original product rather than detracts from it.

    The demo does benefit me, but only indirectly. I get offers to speak at conferences because of but I've never made a dime off of their content. As such it's difficult (for me, anyway) to see how such a product is detrimental to id Software at all. That said, should I ever receive a request from them to remove their content from my site I would do so in a heartbeat.

    Yes, I may be a special case in this. Not everyone will show that same respect to your product. I'm just pointing out that it's not automatically a bad thing. And for the times that it is, that's why we have copyright laws.

  7. @Brandon, sure, you can try to obfuscate the code, but anything that interacts directly with GL (vertex buffers, textures, shaders) are not really protectable against dedicated attackers. I mean, would any of the things you listed stop anyone commenting here? Probably not. But sometimes you have to take some token measures e.g. for contractual obligations.

    The essential futility of DRM-like systems is that content authors can't really distinguish between customers and adversaries, and sometimes give a perverse incentive to reduce the quality of the product in ways so that the legitimate customers suffer and the pirates don't. You definitely want to stay out of this regime.

    I think there are some good signs with respect to DRM being de-emphasized. There is plenty of great, professional content that is available DRM-free (e.g. the entire iTunes library). And you can make money this way. Comic Louis CK just self-published a standup vid and grossed ~2M in ~2 weeks. The Humble Indie bundles have been very successful. Now, DRM seems to be mostly a big-content concern.

    Anyway, content piracy is kind of a good problem to have; you just need to make sure that it doesn't come at a significant opportunity cost. This is why, at WebGL Camp #4, I exhorted everyone to think "Web x GL" instead of "Web + GL." Think of the ways web applications and services have been successful and head in that direction; don't just port desktop OpenGL stuff without thinking about what the potential upsides are.

  8. "Think of the ways web applications and services have been successful and head in that direction; don't just port desktop OpenGL stuff without thinking about what the potential upsides are."

    I should note: this is obviously way easier said than done, so I should at least justify it with a few hand-wavy examples. Typically, successful web products' value propositions have relied on software-as-a-service (effectively, economy of scale) and/or network effects (effectively, user contributed value).

    Something like an MMO would combine both of these effects, but even traditional single-player experiences could benefit. For example, with modding tools, you benefit from user contributed content. In this case, user-to-user interaction is not in the game per se, but is there nonetheless.

    Anyway, if you're just using the web as a distribution mechanism, you're not thinking hard enough.

  9. There is another scenario that I don't think has been mentioned. What if it is the content itself that is being sold? It is a problem similar to what stock photographers have to deal with. There are a number of sites dedicated to selling 3d models for use in other projects. It might be considered advantageous if the models could be visualized directly in the browser instead of looking at static screen shots, yet that opens those models up to the possibility of theft.

  10. Yeah, I touched on such a scenario in the blog but kinda skirted around it. Upon further thought, I think most sights could work something out that allows them the best of both worlds, even utilizing some tricks that the stock photography industry has learned.

    Many times when a sight is selling a model it's going to be distributed in the form of a common modeling tool's format (.3ds, etc) These formats are usually not appropriate for realtime display, so what such a sight may do is have a custom, exported version live on the site for previewing while purchasing gives you the editor-friendly version. True, you could extract the basic model info from the live version if you really wanted to, but that's rather like using the JPEG version of an image instead of the source PSD file. The textures for such models could be watermarked too, such that they give you a decent idea of the final product but discourage anyone from using those textures directly.

  11. Why making solid color textures when you can do the same in shaders?

  12. Also, no way to protect from WebGL Inspector for instance.