Monday, February 9, 2009

Defending against XSS attacks in Freemarker

While Freemarker is quite rich in features, it seems to lack support for programmatically declaring HTML-escaping the default behavior for property access. You need to either add a ?html to every access or wrap every single template into this:


<#escape x as x?html>
... your template code ...
</#escape>


This really has to be done on every file, including those being included such as macro definitions.

Both approaches rely on people remembering to do the right thing, and I don't trust anyone that much, particularly not myself. So instead I decided to add this bit of wrapper code programmatically in the code that loads the template. I took the idea from a posting on the freemarker-user mailing list. Instead of using the normal ClassTemplateLoader, I now do this:


final TemplateLoader templateLoader = new ClassTemplateLoader(this.getClass(), templatePath){
@Override
public Reader getReader(Object templateSource, String encoding) throws IOException {
return new WrappingReader(super.getReader(templateSource, encoding), "<#escape x as x?html>", "");
}
};
configuration.setTemplateLoader(templateLoader);


This uses the following class:


package domain.your.util;

import java.io.IOException;
import java.io.Reader;
import java.util.logging.Level;
import java.util.logging.Logger;

public class WrappingReader extends Reader {

private final Reader originalReader;
private final char[] prologue;
private final char[] epilogue;
private int pos = 0;
private int firstEpilogueChar = -1;
private boolean closed = false;

public WrappingReader(Reader originalReader, char[] prologue, char[] epilogue, Object lock) {
super(lock);
this.originalReader = originalReader;
this.prologue = prologue;
this.epilogue = epilogue;
}

public WrappingReader(Reader originalReader, char[] prologue, char[] epilogue) {
this.originalReader = originalReader;
this.prologue = prologue;
this.epilogue = epilogue;
}

public WrappingReader(Reader originalReader, String prologue, String epilogue, Object lock) {
super(lock);
this.originalReader = originalReader;
this.prologue = prologue.toCharArray();
this.epilogue = epilogue.toCharArray();
}

public WrappingReader(Reader originalReader, String prologue, String epilogue) {
this.originalReader = originalReader;
this.prologue = prologue.toCharArray();
this.epilogue = epilogue.toCharArray();
}

@Override
public int read(char[] cbuf, int off, int len) throws IOException {
if (closed) {
throw new IOException("Reader has been closed already");
}
int oldPos = pos;
Logger.getLogger(getClass().getName()).log(Level.FINE, String.format("Reading %d characters from position %d", len, pos));
if (pos < this.prologue.length) {
final int toCopy = Math.min(this.prologue.length - pos, len);
Logger.getLogger(getClass().getName()).log(Level.FINE, String.format("Copying %d characters from prologue", toCopy));
System.arraycopy(this.prologue, pos, cbuf, off, toCopy);
pos += toCopy;
if (toCopy == len) {
Logger.getLogger(getClass().getName()).log(Level.FINE, "Copied from prologue only");
return len;
}
}
if (firstEpilogueChar == -1) {
final int copiedSoFar = pos - oldPos;
final int read = originalReader.read(cbuf, off + copiedSoFar, len - copiedSoFar);
Logger.getLogger(getClass().getName()).log(Level.FINE, String.format("Got %d characters from delegate", read));
if (read != -1) {
pos += read;
if (pos - oldPos == len) {
Logger.getLogger(getClass().getName()).log(Level.FINE, "We do not reach epilogue");
return len;
}
}
firstEpilogueChar = pos;
}
final int copiedSoFar = pos - oldPos;
final int epiloguePos = pos - firstEpilogueChar;
final int toCopy = Math.min(this.epilogue.length - epiloguePos, len - copiedSoFar);
if((toCopy <= 0) && (copiedSoFar == 0)) {
return -1;
}
Logger.getLogger(getClass().getName()).log(Level.FINE, String.format("Copying %d characters from epilogue", toCopy));
System.arraycopy(this.epilogue, epiloguePos, cbuf, off + copiedSoFar, toCopy);
pos += toCopy;
Logger.getLogger(getClass().getName()).log(Level.FINE, String.format("Copied %d characters, now at position %d", pos-oldPos, pos));
return pos - oldPos;
}

@Override
public void close() throws IOException {
originalReader.close();
closed = true;
}
}


Note that this means that in some cases you might need to escape the escaping, which Freemarker allows with the <#noescape> directive. You also can't use template configuration via the <#ftl> directive anymore, since that would need to be before the <#escape>. Since I never felt the urge to use it, I don't care.

19 comments:

Patrick Co Eban said...

Hi, Great.. Tutorial is just awesome..It is really helpful for a newbie like me.. I am a regular follower of your blog. Really very informative post you shared here. Kindly keep blogging. If anyone wants to become a Java developer learn from Java Training in Chennai. or learn thru Java Online Training from India . Nowadays Java has tons of job opportunities on various vertical industry.

Elizabeth J. Neal said...

hi was just seeing if you minded a comment. i like your website and the thme you picked is super. I will be back. Pflegezusatzversicherung

mithra R said...

Nice post. By reading your blog, i get inspired and this provides some useful information. Thank you for posting this exclusive post for our vision. 
python training Course in chennai
python training in Bangalore
Python training institute in bangalore

jai said...

Well somehow I got to read lots of articles on your blog. It’s amazing how interesting it is for me to visit you very often.
Data Science training in Chennai
Data science training in Bangalore
Data science training in pune
Data science online training
Data Science Interview questions and answers
Data Science Tutorial

jeeva said...

I appreciate your efforts because it conveys the message of what you are trying to say. It's a great skill to make even the person who doesn't know about the subject could able to understand the subject . Your blogs are understandable and also elaborately described. I hope to read more and more interesting articles from your blog.
rpa training in bangalore
best rpa training in bangalore
rpa training in pune | rpa course in bangalore
rpa training in chennai

manisha said...

Awesome article. It is so detailed and well formatted that i enjoyed reading it as well as get some new information too.
Best Devops Training in pune
Devops Training in Bangalore
Microsoft azure training in Bangalore
Power bi training in Chennai

Madhu Balan said...

Great post and informative blog.it was awesome to read, thanks for sharing this great content to my vision.
Good discussion.
Java Training in Chennai
Java Training in Coimbatore
Java Training in Bangalore

Riya Raj said...

Good Blog!!! The way you have conveyed your blog is more impressive...
JAVA Training in Chennai
java class
Best JAVA Training in Chennai
JAVA Training in Tnagar
java training in Thiruvanmiyur
Big data training in chennai
Software testing training in chennai
Android Training in Chennai
Selenium Training in Chennai
Python Training in Chennai

chintu said...

Nice blog, very informative content.Thanks for sharing, waiting for next update...
Photoshop Classes in Chennai
Photoshop Course in Chennai
Photoshop Training in Chennai
Photoshop Training in OMR
Photoshop Training in Porur
Drupal Training in Chennai
Manual Testing Training in Chennai
LoadRunner Training in Chennai
QTP Training in Chennai
C C++ Training in Chennai

lokeshivam said...

Great info. The content you wrote is very interesting to read. This will be loved by all age groups.
DevOps Training in Chennai
R Training in Chennai
Automation Anywhere Training in Chennai
DevOps certification
DevOps Training in Anna Nagar
DevOps Training in Velachery
DevOps Training in Tambaram
DevOps Training in Adyar
DevOps Training in T Nagar

Anbarasan14 said...

Nice post. Thanks for sharing this post with us.
Spoken English Classes in Chennai
Best Spoken English Classes in Chennai
IELTS Coaching in Chennai
IELTS Coaching Centre in Chennai
English Speaking Classes in Mumbai
English Speaking Course in Mumbai
IELTS Classes in Mumbai
IELTS Coaching in Mumbai
IELTS Coaching in Anna Nagar
Spoken English Class in Anna Nagar

diya shivanya said...

This is good information and really helpful for the people who need information about this.
Blockchain Training in Chennai
Blockchain Training Institutes in Chennai
german classes
Best IELTS Coaching in Chennai
learn Japanese in Chennai
Best Spoken English Class in Chennai
Blockchain Training in OMR
Blockchain Training in Porur 

Sadhana Rathore said...

I am very happy to visit your blog. This is definitely helpful, eagerly waiting for more updates.
ccna course in Chennai
ccna Training in Chennai
ccna Training institute in Chennai
AngularJS Training in Chennai
Ethical Hacking course in Chennai
PHP Training in Chennai
ccna Training in Tambaram
ccna Training in Velachery
CCNA course in Anna Nagar

tech updates said...

Good Article
devops training in bangalore
hadoop training in bangalore
iot training in bangalore
machine learning training in bangalore
uipath training in bangalore

Bala said...

Very valuable post...! This information shared is helpful to improve my knowledge skill. Thank you...!
Oracle Training in Chennai
Oracle Certification in Chennai
Tableau Training in Chennai
Oracle DBA Training in Chennai
Linux Training in Chennai
Advanced Excel Training in Chennai
Unix Training in Chennai
Power BI Training in Chennai
Oracle Training in Tambaram
Oracle Training in Thiruvanmiyur

sasi said...

I have to agree with everything in this post. Thanks for useful sharing information.
PHP Training in Chennai
PHP Training in bangalore
php training in coimbatore
PHP Course in Chennai
php Course in madurai
PHP Training Institute in Chennai
php training institute in bangalore
dot net training institutes in bangalore

vinudevan said...

Thanks for giving excellent Message. Waiting for the next article
DOT NET Training in Chennai
c# training in chennai
dot net classes in chennai
mvc training in chennai
dot net training in T nagar
Html5 Training in Chennai
Spring Training in Chennai
Struts Training in Chennai
Wordpress Training in Chennai
SAS Training in Chennai

Tech Guy said...

Nice Post
For Data Science training in Bangalore, Visit:
Data Science training in Bangalore

harish kalyan said...

Very informative blog. Got more information about this technology.
Ionic Training in Chennai
Ionic Training Institute in Chennai
pearson vue test center in chennai
IoT Training in Chennai
Xamarin Training in Chennai
Node JS Training in Chennai
content writing training in chennai
spanish language in chennai
Ionic Training in Anna Nagar
Ionic Training in T Nagar