We build Web & Mobile Applications.
Last week I had the fun of trying to fix what appeared to be random InvalidAuthenticityToken
exceptions coming from a page using Ajax requests. I eventually tracked the problem down to this snippet of JavaScript (and in my defence I didn’t write the code, honest!):
var token = $('new_post').authenticity_token.value;
var post = new Request({url:this.getParent().getParent().getElementsByTagName('form')[0].action}).send('authenticity_token='+token+'&post[content]='+this.value);
Rails generates the authenticity token using the SecureRandom.base64 method provided by ActiveSupport to generate a random string. Unfortunately Base64 strings cannot be used directly in URLs because they contain ‘+‘, ‘/’ and ‘=‘ characters and it was this that was causing the bug: if the authenticity token contained a ‘+’ then it was being interpreted as an URL encoded space causing the exception to occur. Of course JavaScript provides a nice solution to this problem: the encodeURIComponent method.
You may also have noticed there’s another, potentially nasty, related bug lurking in that seemingly innocent bit of JavaScript: the post[content]
parameter isn’t being encoded either. This means that if the user was to enter something like you really should &handle this=properly
then the ampersand would be treated as a new parameter rather than part of the content string. Again encodeURIComponent
comes to the rescue:
var token = $('new_post').authenticity_token.value;
var post = new Request({url:this.getParent().getParent().getElementsByTagName('form')[0].action}).send('authenticity_token='+encodeURIComponent(token)+'&post[content]='+encodeURIComponent(this.value));