lizongbo at 618119.com 工作,生活,Android,前端,Linode,Ubuntu,nginx,java,apache,tomcat,Resin,mina,Hessian,XMPP,RPC

2010年11月29日

使用CRLFFilter过滤HTTP应答头信息名称和值的非法字符防止CRLF注入攻击

Filed under: Java,Web — 标签:, , , , — lizongbo @ 10:02

使用CRLFFilter过滤http应答中头信息名称和值的非法字符,防止CRLF注入攻击
经过测试Resin的response.addHeader方法也没做header名字和值的检查,因此如果webapp代码写法不当的话,将导致CRLF注入攻击,

例如一个页面从url参数中获取地址燃尽进行跳转,如果url地址存在“%0d%0a”编码表示的CRLF而未被检测过滤(java.net.URL解析不会出错,必须用java.net.URI才行),将产生安漏洞。

通过下面的代码可以重现这个Xss漏洞攻击。
jsp代码:
<%
response.addHeader(“X-Locationaaa: http://mqq.im/\r\nX-tesh”,”aaa”);
response.addHeader(“X-Locationbbb: 汉字/\r\nX-teshbbb”,”aaa”);

//下面的goUrl可以从URL的参数中获取,如果url地址存在“%0d%0a”编码表示的CRLF而未被检测过滤(java.net.URL解析不会出错,必须用java.net.URI才行),将产生漏洞。

String goUrl=”http://lizongbo.com/\r\nX-Location: http://618119.com/”;
//goUrl=java.net.URLEncoder.encode(goUrl, “UTF-8”);
response.sendError(403,goUrl);
%>

在Firefox中访问jsp,使用Live HTTP headers 可以看到生成的实际head如下:

HTTP/1.1 403 http://lizongbo.com/
X-Location: http://618119.com/
Server: Resin/4.0.10
X-Locationaaa: http://mqq.im/
X-tesh: aaa
X-Locationbbb: 汉字
X-teshbbb: aaa
Content-Type: text/html; charset=utf-8
Content-Length: 216
Date: Tue, 09 Nov 2010 02:37:48 GMT

因此封装过滤器代码如下:
[code]
package com.lizongbo.web.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;

public class CRLFFilter implements Filter {

@Override
public void destroy() {

}

@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = new CRLFFilterResponseWrapper(
(HttpServletResponse) res);
chain.doFilter(req, response);
}

@Override
public void init(FilterConfig config) throws ServletException {

}

}

[/code]

[code]
package com.lizongbo.web.filter;

import java.io.IOException;
import java.util.Arrays;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

public class CRLFFilterResponseWrapper extends HttpServletResponseWrapper {
/**
* http header name 不允许出现的字符
*/
private static final char[] headerName_tspecials = new char[] { ‘(‘, ‘)’,
‘<‘, ‘>’, ‘@’, ‘,’, ‘;’, ‘:’, ‘\\’, ‘\”‘, ‘/’, ‘[‘, ‘]’, ‘?’, ‘=’,
‘{‘, ‘}’ };
static {
Arrays.sort(headerName_tspecials);
}

HttpServletResponse response = null;

public CRLFFilterResponseWrapper(HttpServletResponse response)
throws IOException {
super(response);
this.response = response;
}

@Override
public void addHeader(String name, String value) {
super.addHeader(filterHeaderName(name), filterHeaderValue(value));
}

@Override
public void sendError(int sc, String msg) throws IOException {
super.sendError(sc, filterHeaderValue(msg));
}

@Override
public void sendRedirect(String location) throws IOException {
super.sendRedirect(filterHeaderValue(location));
}

@Override
public void setHeader(String name, String value) {
super.setHeader(filterHeaderName(name), filterHeaderValue(value));
}

@Override
public void setStatus(int sc, String sm) {
super.setStatus(sc, filterHeaderValue(sm));
}

@Override
public void addDateHeader(String name, long date) {
super.addDateHeader(filterHeaderName(name), date);
}

@Override
public void addIntHeader(String name, int value) {
super.addIntHeader(filterHeaderName(name), value);
}

@Override
public void setDateHeader(String name, long date) {
super.setDateHeader(filterHeaderName(name), date);
}

@Override
public void setIntHeader(String name, int value) {
super.setIntHeader(filterHeaderName(name), value);
}
@Override
public void setContentType(String contentType) {
super.setContentType(filterHeaderValue(contentType));
}

/**
*过滤头信息名字中的非法字符,避免CRLF注入攻击

Many HTTP/1.1 header field values consist of words separated by LWS<br/>
or special characters. These special characters MUST be in a quoted<br/>
string to be used within a parameter value.<br/>

token          = 1*<any CHAR except CTLs or tspecials><br/>

tspecials      = “(” | “)” | “<” | “>” | “@”<br/>
| “,” | “;” | “:” | “\” | <“><br/>
| “/” | “[” | “]” | “?” | “=”<br/>
| “{” | “}” | SP | HT <br/>
CTL            = <any US-ASCII control character<br/>
(octets 0 – 31) and DEL (127)><br/>
SP             = <US-ASCII SP, space (32)><br/>
HT             = <US-ASCII HT, horizontal-tab (9)><br/>

* @param name
* @return
*/
private static String filterHeaderName(String name) {
if (name == null || name.length() < 1) {
return “null”;
}
StringBuilder sb = new StringBuilder(name.length());
for (int i = 0; i < name.length(); i++) {
char c = name.charAt(i);
if (c > 32 && c < 127
&& Arrays.binarySearch(headerName_tspecials, c) < 0) {
sb.append(c);
}
}
return sb.toString();
}

/**
*过滤头信息值中的非法字符,避免CRLF注入攻击

* field-value = *( field-content | LWS )<br/>
*
* field-content = <the OCTETs making up the field-value<br/>
* and consisting of either *TEXT or combinations<br/>
* of token, tspecials, and quoted-string><br/>
*
* @param value
* @return
*/
private static String filterHeaderValue(String value) {
if (value == null || value.length() < 1) {
return “null”;
}
StringBuilder sb = new StringBuilder(value.length());
for (int i = 0; i < value.length(); i++) {
char c = value.charAt(i);
if (c >= 32 && c < 127) {
sb.append(c);
}
}
return sb.toString();
}

public static void main(String[] args) {
String headName = “aaaa aaa\r\n bbb “;
String headvalue = “cccccccccc\r\n ddd”;
System.out.println(headName + “==” + filterHeaderName(headName));
System.out.println(headvalue + “==” + filterHeaderValue(headvalue));
}
}
[/code]

参考链接:

http://www.ietf.org/rfc/rfc2068.txt
http://www.acunetix.com/websitesecurity/crlf-injection.htm
http://comic.sjtu.edu.cn/bbs/view.asp?TID=4118

2010年11月23日

使用zxing生成QRCode二维码,在Android的webview中调用条形码扫描

Filed under: Android,JavaScript,前端开发 — 标签:, , , , — lizongbo @ 21:41

使用zxing生成QRCode二维码,在Android的webview中调用条形码扫描
zxing是一个条形码和二维码生成及识别的java开源组件,QRcode的中文名字是:QR快速响应矩阵码。
1.下载zxing最新的包
到zxing的主页: http://code.google.com/p/zxing/
下载 http://zxing.googlecode.com/files/ZXing-1.6.zip
http://zxing.googlecode.com/files/BarcodeScanner3.52.apk
来源:http://code.google.com/p/zxing/downloads/list
其中BarcodeScanner3.5.2.apk是安装在Android操作系统的手机上的条码扫描器安装包。
条码扫描器的j2me版本下载地址为:
http://zxing.org/w/BarcodeReader.jad
http://zxing.org/w/BarcodeReader.jar

解压为:
D:\Java\zxing-1.6

在dos窗口下进入到:D:\Java\zxing-1.6\core,然后运行ant命令进行编译
(必须先安装配置了ant。
ant最新版的下载地址为:http://ant.apache.org/bindownload.cgi
下载解压后在系统的环境变量中配置ANT_HOME:例如:ANT_HOME=D:\Java\apache-ant-1.7.0;
Path中必须有ant的bin目录,例如:
Path=D:\Java\jdk1.6.0_21\bin;D:\Java\apache-maven-2.0.9\bin;D:\Perl\site\bin;D:\
Perl\bin;D:\Java\apache-ant-1.7.0\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\
System32\Wbem;D:\Programs\svn-win32-1.5.4\bin;C:\Program Files\TortoiseSVN\bin;C
:\Program Files\QuickTime\QTSystem\
)
编译结果如下:
D:\Java\zxing-1.6\core>ant
Buildfile: build.xml

clean:

build:

init:

compile:
[mkdir] Created dir: D:\Java\zxing-1.6\core\build
[javac] Compiling 171 source files to D:\Java\zxing-1.6\core\build
[jar] Building jar: D:\Java\zxing-1.6\core\core.jar

BUILD SUCCESSFUL
Total time: 6 seconds

编译之后得到core.jar这个包。
再进入D:\Java\zxing-1.6\javase目录使用ant进行编译,编译结果如下:
D:\Java\zxing-1.6\javase>ant
Buildfile: build.xml

init:

build:
[mkdir] Created dir: D:\Java\zxing-1.6\javase\build
[javac] Compiling 6 source files to D:\Java\zxing-1.6\javase\build
[jar] Building jar: D:\Java\zxing-1.6\javase\javase.jar

BUILD SUCCESSFUL
Total time: 1 second
编译之后得到javase.jar这个包。

在Eclipse里新建Java工程:

编写java代码如下:
package com.lizongbo.qrcode;

import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Hashtable;

import javax.imageio.ImageIO;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;

public class QRCodeGen {
private static final int BLACK = 0xFF000000;
private static final int WHITE = 0xFFFFFFFF;

/**
* @param args
* @throws WriterException
* @throws IOException
*/
public static void main(String[] args) throws WriterException, IOException {
String picFormat = “png”;
StringBuilder sb = new StringBuilder(1024);
java.io.InputStreamReader fr = new InputStreamReader(
new FileInputStream(“d:\\quickli.vcf”), “GBK”);
BufferedReader br = new BufferedReader(fr);
String line = null;
while ((line = br.readLine()) != null) {
sb.append(line).append(“\r\n”);
}
String str = sb.toString();// 二维码内容
System.out.println(str.length() + “|str==” + str);
str = new String(str.getBytes(“GBK”), “ISO-8859-1”);
String path = “d:/lzb”;
Hashtable hints = new Hashtable();
// hints.put(EncodeHintType.CHARACTER_SET, “GBK”);
BitMatrix bitMatrix = new MultiFormatWriter().encode(str,
BarcodeFormat.QR_CODE, 400, 400, hints);
/**
* begin 这段代码等同于就是 MatrixToImageWriter.writeToFile(bitMatrix, picFormat,
* file);
* 直接这样写就不用引用javase.jar
*/
int width = bitMatrix.getWidth();
int height = bitMatrix.getHeight();
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { image.setRGB(x, y, bitMatrix.get(x, y) ? BLACK : WHITE); } } File file = new File(path + "." + picFormat); ImageIO.write(image, picFormat, file); /** * end 这段代码等同于就是 MatrixToImageWriter.writeToFile(bitMatrix, picFormat, * file); */ MatrixToImageWriter.writeToFile(bitMatrix, picFormat, file); } } 网址的QRcode生成如果不想编写代码,可以使用现成的google的api: http://chart.apis.google.com/chart?chs=150x150&cht=qr&chl=http://zxing.googlecode.com/files/BarcodeScanner3.5.2.apk&chld=L|1&choe=UTF-8 Vcard也可以生成QRcode: 参考:http://blog.yslifes.com/archives/686 在线对二维码进行解码的url: http://zxing.org/w/decode.jspx 在Webview中通过js也可以调用条形码扫描, 封装的java代码如下: final class BarCodeUtilHandler { public void tryGetBarCode() { Intent intent = new Intent("com.google.zxing.client.android.SCAN"); // intent.putExtra("SCAN_MODE", "QR_CODE_MODE"); startActivityForResult(intent, 0); } }; @Override public void onActivityResult(int requestCode, int resultCode, Intent intent) { Log.v(TAG, "onActivityResult===" + requestCode + "," + resultCode + "," + intent); if (requestCode == 0) { if (resultCode == RESULT_OK) { String contents = intent.getStringExtra("SCAN_RESULT"); String format = intent.getStringExtra("SCAN_RESULT_FORMAT"); webview.loadUrl("javascript:showBarCode(\'" + format + "|" + contents + "\')"); } else if (resultCode == RESULT_CANCELED) { webview.loadUrl("javascript:showBarCode(\'没有找到条码!\')"); } } } //webview.addJavascriptInterface(new BarCodeUtilHandler(), "barcodeutil"); //javascript调用:window.barcodeutil.tryGetBarCode(); //function showBarCode(str) { // try { // document.getElementById('data').value=str; // } catch (ee) { // } //}

2010年11月21日

根据sitemap.org的schema使用JAXB生成sitemap.xml的读写方法

Filed under: Java,Web — 标签:, , , , , , — lizongbo @ 13:37

根据sitemap.org的schema使用JAXB生成sitemap.xml的读写方法

sitemap协议的中文说明在:
http://sitemaps.org/zh_CN/protocol.php
对应的schema在:
Sitemap 的 XML 格式定义: http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd
Sitemap 索引文件格式定义:http://www.sitemaps.org/schemas/sitemap/0.9/siteindex.xsd
向google提交sitemap.xml是在:
https://www.google.com/webmasters/tools/home?hl=zh_CN
向百度提交sitemap.xml是在:http://sitemap.baidu.com/

xsd文件生成java代码的操作步骤如下:
1.下载xsd文件保存到D:\dev\xsds。
2.在JDK的bin目录下运行xjc命令生成java文件:
D:\dev\Java\jdk1.6.0_22\bin>xjc -d D:\dev\javasrc -p com.lizongbo.web.sitemaps.sitemap D:\dev\xsds\sitemap.xsd
parsing a schema…
compiling a schema…
com\lizongbo\web\sitemaps\sitemap\ObjectFactory.java
com\lizongbo\web\sitemaps\sitemap\TChangeFreq.java
com\lizongbo\web\sitemaps\sitemap\TUrl.java
com\lizongbo\web\sitemaps\sitemap\Urlset.java
com\lizongbo\web\sitemaps\sitemap\package-info.java

D:\dev\Java\jdk1.6.0_22\bin>xjc -d D:\dev\javasrc -p com.lizongbo.web.sitemaps.siteindex D:\dev\xsds\siteindex.xsd
parsing a schema…
compiling a schema…
com\lizongbo\web\sitemaps\siteindex\ObjectFactory.java
com\lizongbo\web\sitemaps\siteindex\Sitemapindex.java
com\lizongbo\web\sitemaps\siteindex\TSitemap.java
com\lizongbo\web\sitemaps\siteindex\package-info.java
3.将java文件都复制到java工程的src目录的对应包中。
4.将xsd文件复制到java工程的com.lizongbo.web.sitemaps包对应的文件夹中。
5.封装工具类SitemapUtil.java,代码如下:
[code]
package com.lizongbo.web.sitemaps;

import java.io.StringReader;
import java.io.StringWriter;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import org.xml.sax.SAXException;

import com.lizongbo.web.sitemaps.siteindex.Sitemapindex;
import com.lizongbo.web.sitemaps.siteindex.TSitemap;
import com.lizongbo.web.sitemaps.sitemap.TUrl;
import com.lizongbo.web.sitemaps.sitemap.Urlset;
import com.lizongbo.web.sitemaps.sitemap.ObjectFactory;

/**
* 通过jaxb对sitemap.xml进行生成和解析的工具类
*
* @author lizongbo
*
*/
public class SitemapUtil {
private final static ObjectFactory sitemapFac = new ObjectFactory();
private final static com.lizongbo.web.sitemaps.siteindex.ObjectFactory siteindexFac = new com.lizongbo.web.sitemaps.siteindex.ObjectFactory();
private final static String SITEMAP_SCHEMA_LOCATION = “http://www.sitemaps.org/schemas/sitemap/0.9
+ “http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd”;
private final static String SITEINDEX_SCHEMA_LOCATION = “http://www.sitemaps.org/schemas/sitemap/0.9
+ “http://www.sitemaps.org/schemas/sitemap/0.9/siteindex.xsd”;
private final static String DOCTYPE = “<?xml version=\”1.0\” encoding=\”utf-8\”?>”;
private final static String ProcessingInstruction = “<?xml-stylesheet type=’text/xsl’ href=’http://618119.com/wp-content/plugins/google-sitemap-generator/sitemap.xsl’ ?>”;

public static Sitemapindex createSitemapindex() {
return siteindexFac.createSitemapindex();
}

public static TSitemap createTSitemap() {
return siteindexFac.createTSitemap();
}

public static TUrl createTUrl() {
return sitemapFac.createTUrl();
}

public static Urlset createUrlset() {
return sitemapFac.createUrlset();
}

public static String getSitemapXML(Urlset urlset) throws JAXBException,
SAXException {
JAXBContext jc = JAXBContext
.newInstance(“com.lizongbo.web.sitemaps.sitemap”);
Marshaller m = jc.createMarshaller();
StringWriter sw = new StringWriter();
sw.append(DOCTYPE).append(“\n”);
sw.append(ProcessingInstruction).append(“\n”);
//设置xml文本编码
m.setProperty(Marshaller.JAXB_ENCODING, “UTF-8”);
//设置为格式化输出结果
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
//设置为只输出xml节点片段
m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
//指定xsd路径
m.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, SITEMAP_SCHEMA_LOCATION);
SchemaFactory sf = SchemaFactory
.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(SitemapUtil.class
.getResource(“sitemap.xsd”));
//绑定Schema进行校验
m.setSchema(schema);
m.marshal(urlset, sw);
return sw.toString();
}

public static Urlset getUrlset(String xml) throws JAXBException,
SAXException {
JAXBContext jc = JAXBContext
.newInstance(“com.lizongbo.web.sitemaps.sitemap”);
Unmarshaller um = jc.createUnmarshaller();
SchemaFactory sf = SchemaFactory
.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(SitemapUtil.class
.getResource(“sitemap.xsd”));
um.setSchema(schema);
return (Urlset) um.unmarshal(new StringReader(xml));
}

public static String getSitemapindexXML(Sitemapindex sitemapindex)
throws JAXBException, SAXException {
JAXBContext jc = JAXBContext
.newInstance(“com.lizongbo.web.sitemaps.siteindex”);
Marshaller m = jc.createMarshaller();
StringWriter sw = new StringWriter();
sw.append(DOCTYPE).append(“\n”);
sw.append(ProcessingInstruction).append(“\n”);
m.setProperty(Marshaller.JAXB_ENCODING, “UTF-8”);
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
m.setProperty(Marshaller.JAXB_SCHEMA_LOCATION,
SITEINDEX_SCHEMA_LOCATION);
SchemaFactory sf = SchemaFactory
.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(SitemapUtil.class
.getResource(“siteindex.xsd”));
m.setSchema(schema);
m.marshal(sitemapindex, sw);
return sw.toString();
}

public static Sitemapindex getSitemapindex(String xml)
throws JAXBException, SAXException {
JAXBContext jc = JAXBContext
.newInstance(“com.lizongbo.web.sitemaps.siteindex”);
Unmarshaller um = jc.createUnmarshaller();
SchemaFactory sf = SchemaFactory
.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(SitemapUtil.class
.getResource(“siteindex.xsd”));
um.setSchema(schema);
return (Sitemapindex) um.unmarshal(new StringReader(xml));
}

public static void main(String[] args) throws JAXBException, SAXException {
Urlset urlset = SitemapUtil.createUrlset();
TUrl url = SitemapUtil.createTUrl();
url.setLoc(“http://lizongbo.com”);
urlset.getUrl().add(url);
String xml = getSitemapXML(urlset);
System.out.println(xml);
xml = xml.replace(“lizongbo”, “google”);
System.out.println(getSitemapXML(getUrlset(xml)));
Sitemapindex sitemapindex = SitemapUtil.createSitemapindex();
TSitemap tSitemap = SitemapUtil.createTSitemap();
tSitemap.setLoc(“http://618119.com/sitemap.xml”);
sitemapindex.getSitemap().add(tSitemap);
xml = getSitemapindexXML(sitemapindex);
System.out.println(xml);
xml = xml.replace(“lizongbo”, “google”);
System.out.println(getSitemapindexXML(getSitemapindex(xml)));
}
}

[/code]

Older Posts »

Powered by WordPress