This section describes various things that don't work in Caja, along with some workarounds. Some of these are deliberately not supported, some are accidentally not supported. The following material is specific to our Caja instance. Caja has a flexible configuration, so you might not see exactly the same behavior elsewhere.
Caja has two similar but distinct HTML sanitization processes:
innerHTML in your application. Client-side sanitization
is more restrictive, and will silently strip out scripts and
stylesheets.
If your application starts with an <?xml>
tag or a <!DOCTYPE> that isn't HTML, then Caja
will parse your application as XML, which is stricter than HTML, and
stricter than what browsers will usually do.
Most of the time, it's easier to tell Caja that your app is HTML.
Either omit <!DOCTYPE>, or use some HTML
doctype, such as <!DOCTYPE html>.
However, if you do want XHTML strictness, here are some common problems you might encounter:
<script> elements are not
special. In HTML, a <script> element will
read everything as literal text until a closing
</script> tag, so you don't have to do
anything about "<" or "&" characters in your script. In XML,
a <script> element is parsed like any other
tag, and the contents must be well-formed XML. So, you will usually
want to quote your script bodies with
<![CDATA[...]>.<a target=...>
We allow target=_blank and
target=_top. Other values are deleted with a warning.
Omitting target is the same as
target=_top.
<embed>
For Flash, use <yml:swf> instead. Other
embeds are not supported.
<head>
All contents of the head element are stripped.
Use plain HTML starting from inside the body.
<iframe>
Not supported yet. Workaround depends on what you're trying to do.
<link rel=stylesheet>
External stylesheets are not supported yet. Workaround is to inline the stylesheet.
<object>
For Flash, use <yml:swf> instead. Other
embeds are not supported.
<script>
Inline scripts are supported by the server-side cajoler, but they're stripped by the client-side sanitizer. Workaround depends on what you're trying to do.
<script src=...>
External scripts are not supported yet. Workaround is to inline the script.
<style>
Stylesheets are supported by the server-side cajoler, but they're stripped by the client-side sanitizer. Workaround depends on what you're trying to do.
javascript:void(0)
Caja currently rejects any javascript:
URLs.
If you're trying to use javascript:void(0) to
make <a> buttons, try using an onclick handler
instead, something like this:
We currently allow http, https,
and mailto URLs.
This applies to any use of URLs, such as
<a>, <img>, etc.
[] selectors
A subset of [] selectors are supported, but
only to the extent that the browser supports them. For example,
IE7 will still ignore [] selectors.
expression()
Not supported. Workaround depends on what you're trying to do.
@import
Not supported yet. Workaround is to inline the stylesheet.
:visited
The text-decoration property of
:visited is not supported. The following properties
are supported: color, background-color, cursor.
eval()
Not supported. Workaround depends on what you're trying to do.
new Function()
Not supported. This is similar to eval.
Workaround depends on what you're trying to do.
Code like this is not supported:
That's an implicit eval, and has the same
problem as explicit eval.
Instead, put your event-handling code in a function, and assign the function to the event handler:
You can't use names ending with triple-underscore. Those are reserved for Caja's internal bookkeeping.
You can't use names ending with double-underscore. Those are reserved for browser extensions.
with (obj) { ... }
This is not allowed since the dynamic behavior of
with makes it difficult to analyze its security
implications. The workaround is to remove the with
statement and write obj.foo instead of just
foo.
If obj.foo is a method that refers to
this, then peeling it off as a function and calling
it directly will cause a runtime error:
That doesn't really work in raw JavaScript either, but instead of silently doing the wrong thing, Caja will throw an error:
The reason is, JavaScript doesn't have bound methods, so
that code probably doesn't do what you want. The code is saying to
call getElementById with this bound to
the global object, which is window. So if it
succeeded, getElementById would get
this===window, instead of
this===document.
The usual way of capturing a method as a function is to wrap the method call in a function:
And that will work with or without Caja.
Some limitations in the DOM interface result from missing implementation rather than security concerns. If the function or property you're trying to use isn't available, you may be able to do the same thing using currently supported interfaces.
document.write
The document.write method is subject to the
following restrictions:
script, are silently removed. (The same
filtering rules apply to innerHTML.)
document.write('<div class="'); will not work,
nor will document.write(className); or
document.write('">');. Instead, concatenate
the parts and write the result in one piece.
Unbalanced tags, however, are allowed. For example, the following will work:
document.write('<b>'); document.write('hello'); document.write('</b>');
<div id="div1"> <script> document.write('</div>'); </script> <div id="div2"> </div> </div>
A browser would interpret this code by closing
div1, making div2 a
sibling of div1. In Caja, however, the full
structure is created before any scripts are executed, making
div2 a child of div1;
there is no way to change this with
document.write.
document.write to erase
a document. In a browser, if a document is "closed",
document.write erases it and starts a new
document. This typically happens when
document.write is called from an event
listener. In Caja, however, document.write
always appends to the virtual document without erasing
anything.
As an alternative to document.write, you can
use innerHTML:
You can also build up a DOM tree in pieces using
document.createElement and so forth.
window.event
window.event isn't supported. This problem
shows up if you have event-handling code like this:
When you click on the text, the value you get will be
undefined.
The workaround is to pass in the event as an argument. Caja
always binds event within onevent=
handlers, so you can rewrite the example this way:
Another workaround is to use addEventListener
instead.
If your application serves Flash code, it should specify
allowNetworking="internal" in its
<object> and <embed> tags. This
prevents Flash from fetching external pages, images, or JavaScript
routines (which may violate Caja restrictions). For more information
about allowNetworking, see the ActionScript Developer's Guide and Flex documentation from Adobe.