I'd like to describe a recent discovery with regards to using JavaScript with Applets, and running into security problems. First, I'll give an overview of "The Applet Sandbox", and using JavaScript to call into an Applet.
The Sandbox
When developers are introduced to Java Applet technology, one of the first things they learn about is the Java Applet Sandbox. The sandbox refers to a set of security restrictions imposed on an Applet. The sandbox exists to prevent potentially dangerous code from being executed on a user's machine when they simply browse to a website.
Three of the basic restrictions are as follows:
- No access to the client's local file system.
- No network access to a remote system other than the Applet's host machine.
- No access to the client's printer.
There is a way to break out of the sandbox, via signing. A company can establish itself as a trusted vendor by purchasing certificates from a company like VeriSign. You can then "sign" your Applet and have the ability to do things such as read local files, and connect to an arbitrary URL. In order to write the most powerful Java Applets, this is the way to go.
Calling Applet methods via JavaScript
Since Applets are meant to be embedded in web pages, it would be nice to have your web page interact with your Applet. The way to do this is via JavaScript. Here's a really basic example.
Our Applet has one method, changeColor:
public class ColorApplet extends Applet
{
public void changeColor (String color)
{
if (color.equals("red"))
{
setBackground(Color.red);
}
else if (color.equals("blue"))
{
setBackground(Color.blue);
}
}
}
This is a pretty worthless Applet without some kind of external access into the changeColor method. Here's the HTML to call into the method:
<html>
<body>
<applet height="100" width="100" code="ColorApplet.class" name="ColorApplet"></applet>
<a onclick="javascript:ColorApplet.changeColor('red');" href="#">Red</a>
<a onclick="javascript:ColorApplet.changeColor('blue');" href="#">Blue</a>
</body>
</html>
By clicking on the "Red" and "Blue" Links in the html page, the Applet's background would change accordingly.
Using JavaScript to call restricted methods.
Changing colors in an Applet doesn't seem very useful. But lets say I have an Applet that can open up images from a file name or from a URL. The JavaScript hyperlinks can be used to open different files and URLs in the applet. I implemented a public method,
public void openFile (String filename)
This method will open up a local file or URL and display the image in the Applet. This works fine with any filename or URL since our Applet is signed. However, when I tried to call this method from an html page with JavaScript, I got the following error:
java.security.AccessControlException: access denied (java.io.FilePermission C:\images\img1.tif read)
at java.security.AccessControlContext.checkPermission(Unknown Source)
at java.security.AccessController.checkPermission(Unknown Source)
at java.lang.SecurityManager.checkPermission(Unknown Source)
at java.lang.SecurityManager.checkWrite(Unknown Source)
I was baffled. I retested openFile via my file menu, and the image opened up fine, so I knew I had signed the applet properly. I tested the JavaScript again and no luck. Hmm. Then I tried another JavaScript method that simply printed out some text to the console and that worked. Finally, I figured that there must be some additional security layer that prevents JavaScript from calling into the sandbox-restricted methods, even if the Applet is signed. After a quick Google search, I found some forum threads such as this one, which confirmed my suspicions. So what to do? I figured I would use the JavaScript method just to set some properties in the Applet. I would then create a separate thread that could be responsible for listening to changes in these fields, and calling the openFile method on behalf of the JavaScript. Here's how that worked. I made a new method called jsOpenFile, like this:
/**
* @param name
*/
public void jsOpenFile(String name)
{
gJavascriptFilename = name;
gJavascriptCalled = true;
}
Then I defined a thread in the init() method of my applet, like this:
Thread javascriptListener = new Thread()
{
public void run()
{
while (true)
{
if (gJavascriptCalled)
{
gJavascriptCalled = false;
openFile(gJavascriptFilename);
}
try
{
sleep(JAVA_SCRIPT_POLL_INTERVAL);
}
catch (Throwable t)
{
t.printStackTrace();
}
}
}
};
javascriptListener.start();
Sure enough it works!
-Alex
Recent Comments