About DWR's JavaScript Security

DWR offers protection from several JavaScript vulnerabilities out of the box:

DWR's Protection against XSS

All relevant functions in DWR's util.js automatically escape dangerous characters which could be used in an XSS attack. You can read more about how our XSS protection works in our client documentation.

DWR's Protection against the <script> tag hack and CSRF

There are 3 basic ways to protect any service that returns JSON or JavaScript against the <script> tag hack. Some of these methods or more reliable than others but DWR uses a combination of all three out of the box.

DWR Uses a Secret in the Request (provides protection from CSRF attacks)

If you can only support one of these protection methods, this is the one to chose. Including a secret in the request allows the server to reject the request as invalid before any actions take place. It is common to include the secret in the URL, however this is a slightly vulnerable position for a secret since it is likely to turn up in web server log files and so on.

DWR uses a secret in the POST body to allow the server to deny forged requests. (This secret is randomly generated by an algorithm on the server, and the algorithm is pluggable - org.directwebremoting.extend.IdGenerator). The secret in the POST body is compared with a cookie in the request, and if they don't match the request is rejected as a potential CSRF attack. Security comes from a CSRF attackers inability to assign this cookie. You can turn this protection off (to allow cross-domain requests for public data) by setting the crossDomainSessionSecurity=false init-param in web.xml.

DWR Forces pre-eval() Processing

Since <script> tag remoting does not allow you to process the JSON or JavaScript before it is eval()ed you can protect your JSON by forcing it to be manipulated before it is eval()ed. There are 3 ways to do this (DWR implements the first):

  1. Prefix the script with 'throw new Error("message");'. This is the approach taken by DWR and it is a neat solution in that it allows you to explain what is wrong to users that get the message by mistake.
    It is potentially vulnerable to some browser allowing an attacker to redefine the Error or String constructors to prevent the throw from happening, however this does not work on any browser that I know of, and it's hard to see how it could happen.
    DWR uses this method. You can control it using the allowScriptTagRemoting=true init-param in web.xml. There is also an experimental feature 'scriptTagProtection' that allows you to set the prefix used.
  2. Wrap the JSON in a comment. For example, /* { 'data':'protected' } */. When this is eval()ed, there will be no result, however if you have fetched the data using XHR or iframe, you can do some string manipulation before eval() to remove the leading /* and trailing */.
    There are 2 problems with this approach. The first is that it requires manipulation of both ends of the string (the others only require one). The other, more serious, is that if your content could contain '*/', then the comment will terminate early, potentially leaving executable code behind. There could be many innovative ways to exploit this weakness, and it would be a mistake to thing that you were safe based on a trivial analysis.
  3. Prefix the script with 'while(1);'. Since this is an infinite loop, it causes browsers to hang, and maybe give an error message. Either way the script does not get executed.
    There is a potential issue with this solution - that some browser may allow you to override the action of 'while', using something like this: 'function while() {}'. None of the current browsers allow this though.
    Google use this method to protect data in GMail. 'while(1);' is possibly better than 'while(true);' in case there are any browsers that allow you to redefine truth.

DWR Forces POST Requests

Since browsers use GET to process <script> tags, you can prevent <script> tags from working by denying GET requests for some JavaScript resource. This is the most common solution, however it is also perhaps the weakest.

Firstly XHR-POST doesn't work with older versions of Safari, so some support for GET is often useful.

More importantly future versions of Firefox are touted to include cross-domain XHR support. While we don't have exact knowledge of how this will happen, it would be foolish to base your security plans on this technique holding up.

Finally, we're working in an environment where new possibilities are popping up every day - betting your security on a system that works more by fluke than design isn't a great idea in my opinion.

By default DWR denies GET requests for belt and braces security, however this is customizable using the allowGetForSafariButMakeForgeryEasier=true init-param in web.xml.