危险
的。
(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);
}
}
大多数服务器系统,包括Servlet、JSP和EJB,都支持不直接依赖文件系统访问的配置
方法。使用定制的SecurityManager或者使用一个简单的检查脚本(检查程序是否直接
操作文件系统以及是否使用映像API),我们就可以实施“无文件系统直接访问”策略
。尽管大多数应用服务器允许使用文件系统,但一个好的EJB不会使用它。
最后,请务必不要忘记保持数据充分分离、精确定义这一良好的编程习惯。假设我们有
一个用来保存用户信息的数据库,现在需要增加一个字段标示用户是否具有超级用户权
限。如果在原来的表中增加一个列实在过于复杂,采用下面这种方法就变得很有吸引力
:在用户名字中加上一个特殊字符表示用户是否具有特殊权限,当用户登录时检查该特
殊字符,以便防止非法用户宣称自己拥有特殊权限。但事实上,这种做法是非常有害的
。所有的数据域,不管它是在数据库中还是作为局部变量,都应该精确定义且只保存一
份信息。
五、基本原则总结
根据上述讨论,我们得到如下防止出现安全问题的基本原则:
对于各个输入域,严格地定义系统可接受的合法输入字符,拒绝所有其他输入内容。
应该尽可能早地对用户输入进行检查,使得使用危险数据的区域减到最小。
不要依赖浏览器