by Laurence VanhelsuwΓ©

Protecting your applet’s intellectual property

news
Dec 1, 199613 mins
DeveloperJavaSecurity

Is that my apple(t) you've got behind your back?

Designing and writing an applet demands a significantly higher investment in resources than, say, creating simple HTML pages. The same unscrupulous site creators who in the past have copied your HTML designs or the graphics they contained aren’t thinking twice about also incorporating your applets into their sites. If this doesn’t bother you, fine. I’m a strong supporter of the public-domain-software phenomenon, and I’ve contributed several programs myself. But if your applets aren’t meant to be copied the world over, gratis, read on. This article will show you how to put a stop to this type of software piracy.

Java has been the focus of intense scrutiny by Internet security experts looking for loopholes that might expose host systems to malicious, or accidental, security breaches. Package java.langβ€˜s SecurityManager class, the run-time class verification stage, and a language design that rules out corrupting memory (via pointers or out-of-bound array accesses) are the three key mechanisms Java uses to satisfy most people’s concerns. But how does Java help you encase your carefully handcrafted applets with a protective suit of armor? Class Applet, in package java.applet, contains some methods that appear to be just what are needed:

  • public URL getCodeBase()
  • public URL getDocumentBase()

These two methods can be called from within an applet to determine the applet’s origins. getDocumentBase() returns the host that served the Web page containing the applet, and getCodeBase() returns the host that served the applet class files themselves. In the vast majority of cases these two hosts are the same, but this doesn’t have to be the case, since the HTML tag allows an optional CODEBASE parameter that can point to a different server than the one that served the Web page.

When Joe Hacker comes along and decides he wants to put your applet on his Web pages (or on those of the unsuspecting client he’s working with), he can do one of two things:

  • After visiting the page containing your applet, he can find the applet class files in his browser’s on-disk cache and copy them, so that his pages can refer to the applet as a local applet. With Netscape Navigator, for example, he needs to only find out which of the cryptically renamed CLA files belong to the applet. Since all Java class files contain their own name in the file itself, this poses no great challenge to Joe Hacker.

  • He can avoid the first option altogether and simply let his tags point to your applet, on your server. This will tax your server on behalf of the pirate’s, adding insult to injury!

In the last instance, a call to getCodeBase() will return the same URL as when called when your applet is run from your own Web pages by clients. This means that basing your applet’s copy-protection scheme on one or more calls to getCodeBase() is not foolproof. Only when relying on getDocumentBase() can your applets find out whether they have been enslaved by unprincipled others.

Based on our current knowledge, we can implement a simple test embedded in an applet’s init() initialization routine to check that the Web page the applet is born into is the page the applet expects:

import java.awt.*; import java.net.*; import java.applet.*;

public class NaiveProtection extends Applet {

private boolean pirated;

public void init() { String host, message;

// Determine if the document we were embedded in is located on // our server. If not, then someone grabbed our applet without // asking us.

host = getDocumentBase().getHost(); pirated = ! host.equals("www.javaworld.com");

if (pirated) { message = "Today I'm striking."; } else { message = "All systems go !"; }

add(new Label(message)); // print message as a centered label } } // End of Class NaiveProtection

This applet will simply demonstrate awareness of its whereabouts by printing either β€œAll systems go!” when the applet is embedded in its legitimate Web page, or β€œToday I’m striking” if not. Here it is in action:

You need a Java-enabled browser to view this applet.

Does this solve the problem of applet piracy? Let’s watch over Joe Hacker’s shoulder as he tackles the applet’s defensive systems.

The hacker’s equivalent of the screwdriver is a hexadecimal dump (hexdump for short) and edit utility, so the first thing a hacker bent on ripping off your applet will do is run your applet through his favorite hexdumper. Here’s the hexdump output of file NaiveProtection.class:

0000: CA FE BA BE 00 03 00 2D 00 36 08 00 26 08 00 2B   .......-.6..&..+
0010: 08 00 35 07 00 23 07 00 2A 07 00 2F 07 00 33 07   ..5..#..*../..3.
0020: 00 1D 07 00 2E 09 00 07 00 14 0A 00 06 00 15 0A   ................
0030: 00 05 00 13 0A 00 09 00 16 0A 00 08 00 17 0A 00   ................
0040: 09 00 11 0A 00 04 00 12 0C 00 32 00 24 0C 00 29   ..........2.$..)
0050: 00 22 0C 00 32 00 2C 0C 00 27 00 20 0C 00 1C 00   ."..2.,..'. ....
0060: 21 0C 00 1F 00 2D 0C 00 31 00 18 01 00 2A 28 4C   !....-..1....*(L
0070: 6A 61 76 61 2F 61 77 74 2F 43 6F 6D 70 6F 6E 65   java/awt/Compone
0080: 6E 74 3B 29 4C 6A 61 76 61 2F 61 77 74 2F 43 6F   nt;)Ljava/awt/Co
0090: 6D 70 6F 6E 65 6E 74 3B 01 00 14 4E 61 69 76 65   mponent;...Naive
00A0: 50 72 6F 74 65 63 74 69 6F 6E 2E 6A 61 76 61 01   Protection.java.
00B0: 00 0F 4C 69 6E 65 4E 75 6D 62 65 72 54 61 62 6C   ..LineNumberTabl
00C0: 65 01 00 0A 45 78 63 65 70 74 69 6F 6E 73 01 00   e...Exceptions..
00D0: 07 67 65 74 48 6F 73 74 01 00 12 6A 61 76 61 2F   .getHost...java/
00E0: 61 77 74 2F 43 6F 6E 74 61 69 6E 65 72 01 00 0D   awt/Container...
00F0: 43 6F 6E 73 74 61 6E 74 56 61 6C 75 65 01 00 0F   ConstantValue...
0100: 67 65 74 44 6F 63 75 6D 65 6E 74 42 61 73 65 01   getDocumentBase.
0110: 00 01 5A 01 00 14 28 29 4C 6A 61 76 61 2F 6C 61   ..Z...()Ljava/la
0120: 6E 67 2F 53 74 72 69 6E 67 3B 01 00 15 28 4C 6A   ng/String;...(Lj
0130: 61 76 61 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74 3B   ava/lang/Object;
0140: 29 5A 01 00 10 6A 61 76 61 2F 6C 61 6E 67 2F 53   )Z...java/lang/S
0150: 74 72 69 6E 67 01 00 03 28 29 56 01 00 0A 53 6F   tring...()V...So
0160: 75 72 63 65 46 69 6C 65 01 00 11 77 77 77 2E 6A   urceFile...www.j
                                       ^^ ^^ ^^ ^^ ^^
0170: 61 76 61 77 6F 72 6C 64 2E 63 6F 6D 01 00 07 70   avaworld.com...p
      ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^
0180: 69 72 61 74 65 64 01 00 04 69 6E 69 74 01 00 06   irated...init...
0190: 65 71 75 61 6C 73 01 00 0E 6A 61 76 61 2F 61 77   equals...java/aw
01A0: 74 2F 4C 61 62 65 6C 01 00 15 54 6F 64 61 79 2C   t/Label...Today,
01B0: 20 49 27 6D 20 73 74 72 69 6B 69 6E 67 2E 2E 01    I'm striking...
01C0: 00 15 28 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74   ..(Ljava/lang/St
01D0: 72 69 6E 67 3B 29 56 01 00 10 28 29 4C 6A 61 76   ring;)V...()Ljav
01E0: 61 2F 6E 65 74 2F 55 52 4C 3B 01 00 12 6A 61 76   a/net/URL;...jav
01F0: 61 2F 61 70 70 6C 65 74 2F 41 70 70 6C 65 74 01   a/applet/Applet.
0200: 00 0C 6A 61 76 61 2F 6E 65 74 2F 55 52 4C 01 00   ..java/net/URL..
0210: 04 43 6F 64 65 01 00 03 61 64 64 01 00 06 3C 69   .Code...add...<i
0220: 6E 69 74 3E 01 00 0F 4E 61 69 76 65 50 72 6F 74   nit>...NaiveProt
0230: 65 63 74 69 6F 6E 01 00 0E 4C 6F 63 61 6C 56 61   ection...LocalVa
0240: 72 69 61 62 6C 65 73 01 00 10 41 6C 6C 20 73 79   riables...All sy
0250: 73 74 65 6D 73 20 67 6F 20 21 00 01 00 07 00 09   stems go !......
0260: 00 00 00 01 00 02 00 27 00 20 00 00 00 02 00 01   .......'. ......
0270: 00 28 00 24 00 01 00 30 00 00 00 6C 00 04 00 03   .(.$...0...l....
0280: 00 00 00 38 2A B6 00 0D B6 00 0B 4C 2A 2B 12 01   ...8*......L*+..
0290: B6 00 10 99 00 07 03 A7 00 04 04 B5 00 0A 2A B4   ..............*.
02A0: 00 0A 99 00 09 12 02 4D A7 00 06 12 03 4D 2A BB   .......M.....M*.
02B0: 00 05 59 2C B7 00 0C B6 00 0E 57 B1 00 00 00 01   ..Y,......W.....
02C0: 00 1A 00 00 00 22 00 08 00 00 00 10 00 08 00 11   ....."..........
02D0: 00 1A 00 13 00 21 00 14 00 24 00 13 00 27 00 16   .....!...$...'..
02E0: 00 2A 00 19 00 37 00 09 00 01 00 32 00 24 00 01   .*...7.....2.$..
02F0: 00 30 00 00 00 1D 00 01 00 01 00 00 00 05 2A B7   .0............*.
0300: 00 0F B1 00 00 00 01 00 1A 00 00 00 06 00 01 00   ................
0310: 00 00 05 00 01 00 25 00 00 00 02 00 19   ......%......

Since Joe knows he got your applet from the JavaWorld site (www.javaworld.com), and since he also knows your applet refuses to budge when he tries to coerce it into his pages, one of the first things he will spot in the hexdump is the string www.javaworld.com at hex offset 16B (line 160). Greedily rubbing his hands, he now patches the NaiveProtection.class file to contain www.hacker.com and bingo! β€” this applet will refuse to work from your site and will think nothing of running from www.hacker.com.

Did you expect Java’s class loaders to detect such tampering? To be honest, I did too. But neither Sun’s JDK appletviewer, Netscape Navigator 3.0, nor Microsoft Internet Explorer 3.0 blinks an eye at the hacked class; they all happily load the class, thus potentially creating a security loophole. Maybe String constants are not part of class loaders’ security focus? Let’s try to hack an integer embedded in code itself. Here’s the Java program that we’ll hack:

public class HackTest {

public static void main (String[] args) {

System.out.println(2880293630L);

}} // End of Class HackTest

The long magic constant, 2880293630L, happens to be represented in hexadecimal by 0xABADCAFE, so it is easy to spot in the bytecode executable (as well as having tongue-in-cheek qualities perfectly tailored to Java):

0000: CA FE BA BE 00 03 00 2D 00 20 07 00 17 07 00 1E   .......-. ......
0010: 07 00 0E 07 00 16 09 00 03 00 09 0A 00 01 00 08   ................
0020: 0A 00 02 00 0C 0C 00 15 00 13 0C 00 1D 00 0F 05   ................
0030: 00 00 00 00 AB AD CA FE 0C 00 0D 00 1F 01 00 06   ................
                  ^^ ^^ ^^ ^^
0040: 3C 69 6E 69 74 3E 01 00 10 6A 61 76 61 2F 6C 61   &ltinit>...java/la
0050: 6E 67 2F 53 79 73 74 65 6D 01 00 15 4C 6A 61 76   ng/System...Ljav
0060: 61 2F 69 6F 2F 50 72 69 6E 74 53 74 72 65 61 6D   a/io/PrintStream
0070: 3B 01 00 16 28 5B 4C 6A 61 76 61 2F 6C 61 6E 67   ;...([Ljava/lang
0080: 2F 53 74 72 69 6E 67 3B 29 56 01 00 0D 48 61 63   /String;)V...Hac
0090: 6B 54 65 73 74 2E 6A 61 76 61 01 00 0D 43 6F 6E   kTest.java...Con
00A0: 73 74 61 6E 74 56 61 6C 75 65 01 00 04 28 4A 29   stantValue...(J)
00B0: 56 01 00 0F 4C 69 6E 65 4E 75 6D 62 65 72 54 61   V...LineNumberTa
00C0: 62 6C 65 01 00 07 70 72 69 6E 74 6C 6E 01 00 08   ble...println...
00D0: 48 61 63 6B 54 65 73 74 01 00 13 6A 61 76 61 2F   HackTest...java/
00E0: 69 6F 2F 50 72 69 6E 74 53 74 72 65 61 6D 01 00   io/PrintStream..
00F0: 0A 45 78 63 65 70 74 69 6F 6E 73 01 00 0A 53 6F   .Exceptions...So
0100: 75 72 63 65 46 69 6C 65 01 00 04 6D 61 69 6E 01   urceFile...main.
0110: 00 0E 4C 6F 63 61 6C 56 61 72 69 61 62 6C 65 73   ..LocalVariables
0120: 01 00 04 43 6F 64 65 01 00 03 6F 75 74 01 00 10   ...Code...out...
0130: 6A 61 76 61 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74   java/lang/Object
0140: 01 00 03 28 29 56 00 01 00 04 00 02 00 00 00 00   ...()V..........
0150: 00 02 00 09 00 1A 00 10 00 01 00 1C 00 00 00 26   ...............&
0160: 00 03 00 01 00 00 00 0A B2 00 05 14 00 0A B6 00   ................
0170: 06 B1 00 00 00 01 00 14 00 00 00 0A 00 02 00 00   ................
0180: 00 05 00 09 00 03 00 01 00 0D 00 1F 00 01 00 1C   ................
0190: 00 00 00 1D 00 01 00 01 00 00 00 05 2A B7 00 07   ............*...
01A0: B1 00 00 00 01 00 14 00 00 00 06 00 01 00 00 00   ................
01B0: 01 00 01 00 19 00 00 00 02 00 11   ...........

Our constant is right at the beginning of the file, at hex offset 34. When modifying this constant, again I found no Java virtual machine (JVM) that would protest at the class file tampering!

For any applet copy protection schemes, what this means is that even using a numeric address for your server in the getDocumentBase() check will not stop a hacker from simply modifying the numeric IP address embedded anywhere in your applet.

What’s more, any approach that embeds the exact document’s address (in whatever shape or form) in the applet will be vulnerable from a maintenance point of view. If your site needs to be moved to a machine with a different IP address, the applet has to be recompiled with the new address. If your Webmasters are all Java experts, then you don’t have a problem, but if your site was built by an external bureau (HTML, applets, and maintenance utilities included), then you might have a problem since your organization usually will not have access to the Java sources, preventing you from attempting any in-house recompilations.

To stay clear of having to recompile applets, one solution would be to keep an external β€œkey” that unlocks the applet whenever clients visit pages containing your applet. One convenient place to hold the key (from a maintenance point of view) would be right in the HTML for the page itself, as a PARAM applet parameter.

For example:

<APPLET CODE=ReallyValuableApplet.class WIDTH=640 HEIGHT=400>

<PARAM NAME=Key VALUE=2F70B485AD3E016C>

</APPLET>

This exposed key is only the public half of the real β€œkey.” This counter-intuitive approach is called public key cryptography and is used by systems like Phil Zimmerman’s Pretty Good Privacy (PGP) package. The above example shows a hypothetical binary key that is 64 bits long. This key is encrypted to refer to your Web site and nobody else’s. The weak link in this scheme now shifts from your applet’s transparent internals (transparent to a hacker) to the cryptographic system used to map the key to your Web site’s address. And while no system is hack- or tamper-proof, you can now deploy industry- or even military-grade encryption algorithms (if you dare; some authoritarian countries have laws forbidding the use, import, and/or export of such cryptographic systems) to encode your keys and use matching decryption algorithms in your applet to check the key against getDocumentBase()β€˜s output.

The following example applet can act as a template or base class for such an HTML-embedded key approach. It goes without saying that actually trying to provide a complete and watertight implementation, right here and for all to see, would be a self-defeating exercise.

The applet below therefore is just a mockup of the real thing. Its boolean keyFitsURL() method does not even pretend to be a defense against applet hackers. You should replace the implementation of this black box with something that is as secure and complex as needed. Reverse-engineering tools like Hanpeter Van Vliet’s sublime and controversial Mocha class decompiler make Joe Hacker’s life easy; the only way to ensure that hackers still face a proverbial brick wall is to code the algorithm in such a way that the vast majority of hackers won’t understand it β€” even with the source code in front of them. Luckily, with state of the art encryption algorithms, incomprehensibility is almost a given for most mortal programmers.

Implementing your own keyFitsURL() method also allows you to determine the exact format and contents of the β€œKey” PARAM parameter. A security-enhancing possibility would be to encode extra information in the key (such as passwords), so that the key-to-Web site mapping becomes more convoluted and harder to crack.

Here is the source for the template CopyProtectedApplet.

And here is the applet in action (try embedding it in your own page to convince yourself it does require an encrypted key):

<P>
<CENTER>
<APPLET CODE=TryStealingMe.class WIDTH=300 HEIGHT=100>
<PARAM NAME=KEY VALUE=825469847 >
</APPLET>
</CENTER>

Try me.

Recipe for protection

To transform the technique presented above into something

approaching

a realistic protection scheme, you could further complicate matters for Joe Hacker by trying the following recipe:

  1. Before you do anything, check the location for bugging devices. (Check that the applet is really running in a plain browser, and not inside a hacker’s harness that has getDocumentBase() patched.)

  2. Sprinkle protection code throughout your entire applet, relying on a web of interconnected checks, instead of a single (vulnerable) method. Like the Internet itself, this technique is resilient to localized attacks.

  3. Thoroughly mix in the applet’s length and contents (using checksumming algorithms) in your checks. Any modifications to the applet itself should be detectable.

  4. Pass your applet through a grinder β€” an obfuscating utility. Han Peter Van Vliet has written such a tool in response to his own Mocha decompiler.

  5. Separate your mixture into client (applet) and server halves. Cracking the applet without having the complementary serving system would further thwart Joe Hacker (but might now logically invite him to focus on your server!).

  6. Brighten things up by hiding keys in images and/or sounds.

  7. Add chunks of native code for good measure, according to taste.

  8. Finally, package the lot in a jar file β€” a compact Java archive for packaging the components of a Java application that can be selectively digitally signed. (Available soon from your local Java grocer.)

Conclusion

Security is a constantly moving target. The moment anyone claims to have invented the ultimate Fort Knox protection, a horde of amateur and professional, benign and not so benign security experts starts working on breaking the novel scheme. History has shown this to be a case of unbounded co-evolution: while there are people who insist on keeping things in locked boxes, there are also people who insist on picking those boxes’ locks. When you think you devised a clever protection mechanism, know that the other game players are just awaiting their turn to move.

Laurence VanhelsuwΓ© is an independent software engineer. Self-taught, he dropped out of college and immediately started a professional career writing arcade games. He has worked on such diverse technologies as X.25 WAN routers, virtual reality flight simulation, Postscript, and realtime digitized video-based traffic analysis. Laurence thinks Java will revolutionize computer science by leveling the computing landscape into one pan-Java playing field.