时应该非常小心
字符串被解释执行的问题可能在允许嵌入脚本代码的任何环境中出现。例如,这类问题
可能在Xalan(也称为LotusXSL)中出现,当然这是指系统设置不严格、易受攻击的情
况下。
Xalan的脚本支持能够关闭(而且这是Xalan的默认设置),在敏感的应用中关闭脚本支
持是一种明智的选择。当你需要用DOM处理XML文档时还必须考虑到另外一点:DOM保证
所有文本都经过正确的转义处理,防止非法的标记插入到脚本之内。LotusXSL缺乏这个
功能,但这绝不是一个BUG。支持脚本是LotusXSL的一个特色,而且它(明智地)默认
处于关闭状态。XSL的W3C规范并没有规定支持脚本的能力。
现在我们来看看字符串解释执行如何影响SQL和JDBC。假设我们要以用户名字和密码为
条件搜索数据库中的用户,Listing 5的Servlet代码看起来不错,但事实上它却是危险
的。
(Listing 5)
String user = request.getAttribute("username");
String pass = request.getAttribute("password");
String query = "SELECT id FROM users WHERE
username="+user+" AND password="+pass;
Statement stmt = con.createStatement(query);
ResultSet rs = con.executeQuery(query);
if (rs.next())
{
// 登录成功
int id = rs.getInt(1);
...
}
else
{
// 登录失败
...
}
如果用户输入的查询条件中,用户名字等于“fred”,密码等于“something”,则系
统执行的查询实际上是:
SELECT id FROM users WHERE
username='fred' AND password=
'something'
这个查询能够正确地对用户名字和密码进行检查。但是,如果用户输入的查询条件中,
名字等于“fred' AND ('a'='b”,密码等于“blah') OR 'a'='a”,此时系统执行的
查询变成了:
SELECT id FROM users
WHERE username='fred' AND (
'a'='b' AND password='blah') OR 'a'='a'
可以看出,这个查询无法正确地对用户名字和密码进行检查。Listing 6的代码要安全
得多,它从根本上防止了用户修改SQL命令逃避检查。
(Listing 6)
String user = request.getAttribute("username");
String pass = request.getAttribute("password");
String query = "SELECT id FROM users
WHERE username=? AND password=?";
PreparedStatement stmt = con.prepareStatement(query);
stmt.setString(1, user);
stmt.setString(2, pass);
ResultSet rs = stmt.executeQuery();
...
所有对文件系统的访问都是字符串可能被解释执行的地方。用Java访问文件系统时,我
们应该注意文件的命名方式。Listing 7是一个可能带来危险的例子。这个程序根据用
户输入决定读取哪个文件,它的危险就在于攻击者能够输入“../../../etc/passwd”
这样的文件名字并获得系统的密码文件。这可不是我们希望出现的事情。预防出现这种
安全漏洞最简单的方法是:除非绝对需要,否则不要使用平面文件(Flat File)。
(Listing 7)
public class UnsafeServlet
{
public void doGet(HttpServletRequest request,
HttpServletResponse response)
{
String product = request.getAttribute("product");
Reader fin = new FileReader(
"/usr/unsafe/products/"+ product);
BufferedReader in = new BufferedReader(fin);
String cost = in.readLine();
// 其他处理过程
response.getWriter().println(cost);
}
}