I hear all the time that java does not have any good encoding libraries but have used some frameworks that do seem to encode the output properly. If anyone uses the struts framework and implements it properly then all your output is encoded properly if you use the following methods to output data.
<bean:write name="secData" property="username"/><br>
<html:link href="./test.jsp" paramId="test" paramName="secData" paramProperty="username" > <bean:write name="secData" property="username"/></html:link><br>
<html:hidden name="secData" property="username" /> <br>
The tag libraries bead:write, html:hidden, and html:link will all output either url encoded output for html:link (which creates an anchor tag) and html:hidden or will entity encode your output for bean:write.
What if your not using struts you ask?
Well this is great if you are using struts 1 and struts 2 (output tags are different for struts 2) but what you are not or you are writing servlets that generate html dynamically. This is not a problem. I dug a little deeper into struts to see what struts was doing and if there is a way to leverage this for other sites that do not use this framework. The URL encoding is simply URLEncode.encode( your string, your format). Its uses a default java class that has been around since 1.5. Just import java.net.URLEncoder.
Example:
String output = URLEncoder.encode("your String" , "UTF-8");
Struts 1 is using an entity encoder built specifically into the struts framework. The entity encoding is using a struts class called ResponseUtils. So you could import this class and still not use the struts MVC architecture.
Example:
String output = org.apache.struts.util.ResponseUtils.filter("your string");
Struts 2 does entity encoding by using a class TextUtils from WebWork. Import org.opensymphony.xwork2.util.TextUtils
Example:
String output = org.opensymphony.xwork2.util.TextUtils.htmlEncode("your string", true);
Proper Encoding with international Chars!!!!
There are other encoding options provided by the apache commons lang library. This is library is probably the most useful. To get it to properly encode international chars to the screen you need to first unescape the html before to escape the html. import org.apache.commons.lang.StringEscapeUtils;
Example:
String Output = StringEscapeUtils.escapeHtml(StringEscapeUtils.unescapeHtml(input));
Below is an example screenshot of the all above encodings in a simple servlet. Notice that StringEscapeUtils (the last one) will properly encode the xss attempt plus the Chinese character set. This will solve the problem all you java developers have with output encoding international characters and can quit complaining that there isn't any good encoding options for java. =) My source code is attached here: http://my-security-projects.googlecode.com/files/testEncoding.war
I hope this finally answers everyone's concerns for international character encoding in java. I'll let you all out there in the hacker community see if you can find a way to get past this model. Let me know if you do
Here is the page source:
<html><body>
<h1> Servlet Test </h1>
<br><b>Input String: </b> <script>alert('xss');</script> 环球经济不景
气中国经济增长放缓 中国经济
在环球不景气下呈现放缓态势
,最新国内生产总值增长为9.9%,
通胀持续放缓。 中国九月贸易
盈余创纪录 访谈:中国外贸前
景不容乐观 金融风暴:中国面
临的危机与机遇
<br>
<b>java.net.URLEncoded: </b>%3Cscript%3Ealert%28%27xss%27%29%3B%3C%2Fscript%3E+++
%26%2329615%3B%26%2329699%3B%26%2332463%3B%26%2327982%3B%26%2319981%3B%26%2326223%3B
%26%2327668%3B%26%2320013%3B%26%2322269%3B%26%2332463%3B%26%2327982%3B%26%2322686%3B
%26%2338271%3B%26%2325918%3B%26%2332531%3B+%26%2320013%3B%26%2322269%3B%26%2332463
%3B%26%2327982%3B%26%2322312%3B%26%2329615%3B%26%2329699%3B%26%2319981%3B%26%2326223
%3B%26%2327668%3B%26%2319979%3B%26%2321576%3B%26%2329616%3B%26%2325918%3B%26%2332531
%3B%26%2324577%3B%26%2321183%3B%26%2365292%3B%26%2326368%3B%26%2326032%3B%26%2322269
%3B%26%2320869%3B%26%2329983%3B%26%2320135%3B%26%2324635%3B%26%2320540%3B%26%2322686
%3B%26%2338271%3B%26%2320026%3B9.9%25%26%2365292%3B%26%2336890%3B%26%2332960%3B%26
%2325345%3B%26%2332493%3B%26%2325918%3B%26%2332531%3B%26%2312290%3B+%26%2320013%3B
%26%2322269%3B%26%2320061%3B%26%2326376%3B%26%2336152%3B%26%2326131%3B%26%2330408
%3B%26%2320313%3B%26%2321019%3B%26%2332426%3B%26%2324405%3B+%26%2335775%3B%26
%2335848%3B%26%2365306%3B%26%2320013%3B%26%2322269%3B%26%2322806%3B%26%2336152%3B%26
%2321069%3B%26%2326223%3B%26%2319981%3B%26%2323481%3B%26%2320048%3B%26%2335266%3B+
%26%2337329%3B%26%2334701%3B%26%2339118%3B%26%2326292%3B%26%2365306%3B%26%2320013%3B
%26%2322269%3B%26%2338754%3B%26%2320020%3B%26%2330340%3B%26%2321361%3B%26%2326426%3B
%26%2319982%3B%26%2326426%3B%26%2336935%3B+
<br>
<b>(apache commons lang) org.apache.commons.lang.StringEscapeUtils: </b><script>alert('xss');</script>
&#29615;&#29699;&#32463;&#27982;&#19981;&#26223;&#27668;&#20013;&#22269;&#32463;
&#27982;&#22686;&#38271;&#25918;&#32531; &#20013;&#22269;&#32463;&#27982;&#22312;
&#29615;&#29699;&#19981;&#26223;&#27668;&#19979;&#21576;&#29616;&#25918;&#32531;
&#24577;&#21183;&#65292;&#26368;&#26032;&#22269;&#20869;&#29983;&#20135;&#24635;
&#20540;&#22686;&#38271;&#20026;9.9%&#65292;&#36890;&#32960;&#25345;&#32493;&#25918;
&#32531;&#12290; &#20013;&#22269;&#20061;&#26376;&#36152;&#26131;&#30408;&#20313;
&#21019;&#32426;&#24405; &#35775;&#35848;&#65306;&#20013;&#22269;&#22806;&#36152;
&#21069;&#26223;&#19981;&#23481;&#20048;&#35266; &#37329;&#34701;&#39118;&#26292;
&#65306;&#20013;&#22269;&#38754;&#20020;&#30340;&#21361;&#26426;&#19982;&#26426;
&#36935;
<br>
<b>(struts-core-1.3.8.jar) org.apache.struts.util.ResponseUtils: </b><script>alert('xss');</script>
&#29615;&#29699;&#32463;&#27982;&#19981;&#26223;&#27668;&#20013;&#22269;&#32463;
&#27982;&#22686;&#38271;&#25918;&#32531; &#20013;&#22269;&#32463;&#27982;&#22312;
&#29615;&#29699;&#19981;&#26223;&#27668;&#19979;&#21576;&#29616;&#25918;&#32531;
&#24577;&#21183;&#65292;&#26368;&#26032;&#22269;&#20869;&#29983;&#20135;&#24635;
&#20540;&#22686;&#38271;&#20026;9.9%&#65292;&#36890;&#32960;&#25345;&#32493;&#25918;
&#32531;&#12290; &#20013;&#22269;&#20061;&#26376;&#36152;&#26131;&#30408;&#20313;
&#21019;&#32426;&#24405; &#35775;&#35848;&#65306;&#20013;&#22269;&#22806;&#36152;
&#21069;&#26223;&#19981;&#23481;&#20048;&#35266; &#37329;&#34701;&#39118;&#26292;
&#65306;&#20013;&#22269;&#38754;&#20020;&#30340;&#21361;&#26426;&#19982;&#26426;
&#36935;
<br>
<b>(xwork) com.opensymphony.xwork2.util.TextUtils with spec chars: </b><script>alert('xss');</script>
&#29615;&#29699;&#32463;&#27982;&#19981;&#26223;&#27668;&#20013;&#22269;&
#32463;&#27982;&#22686;&#38271;&#25918;&#32531; &#20013;&#22269;&#32463;&#27982;
&#22312;&#29615;&#29699;&#19981;&#26223;&#27668;&#19979;&#21576;&#29616;&#25918;
&#32531;&#24577;&#21183;&#65292;&#26368;&#26032;&#22269;&#20869;&#29983;&#20135;
&#24635;&#20540;&#22686;&#38271;&#20026;9.9%&#65292;&#36890;&#32960;&#25345;&
#32493;&#25918;&#32531;&#12290; &#20013;&#22269;&#20061;&#26376;&#36152;&#26131;
&#30408;&#20313;&#21019;&#32426;&#24405; &#35775;&#35848;&#65306;&#20013;&
#22269;&#22806;&#36152;&#21069;&#26223;&#19981;&#23481;&#20048;&#35266; &#37329;
&#34701;&#39118;&#26292;&#65306;&#20013;&#22269;&#38754;&#20020;&#30340;&#21361;
&#26426;&#19982;&#26426;&#36935;
<br>
<b>apache commons unescape then escape with StringEscapeUtils: </b><script>alert('xss');</script>
环球经济不景气中国经济增长放
缓 中国经济在环球不景气下呈现
放缓态势,最新国内生产总值增
长为9.9%,通胀持续放缓。 中国九
月贸易盈余创纪录 访谈:中国外
贸前景不容乐观 金融风暴:中国
面临的危机与机遇
<br>
<form action="AscetikServlet" method="POST" >
<input type="text" id="input" name="input" >
<input type="submit" >
</form>
</body>
</html>
References:
Apache Commons Lang: http://commons.apache.org/lang/
Struts 1: http://struts.apache.org/
Struts 2: http://struts.apache.org/2.x/
WebWork: http://www.opensymphony.com/webwork/
Mycode: http://my-security-projects.googlecode.com/files/testEncoding.war
My code is written for tomcat 6 with java 1.6 and all the above libraries.
2 comments:
I have one update to this. Bean write does not cover all the character sets as well as the apache commons libraries do. Just a note to think about.
A decent alternative for output encoding can be found in OWASP Enterprise Security API. It's really easy to use and adapt to whatever context you need.
Post a Comment