1.CERT-J输入验证和数据净化,需要解决sql注入问题
SQL注入漏洞的出现是因为生成的SQL查询语句部分元素来自非受信源。在没有防范的情况下,来自非受信源的数据可能恶意串改SQL查询语句,导致了信息的泄露和数据的更改.
假设一个系统对用户进行身份验证,通过如下查询语句访问SQL数据库。如果查询返回任何结果,则验证成功,否则,身份验证失败。
SELECT * FROM db_user WHERE username='<USERNAME>' AND password='<PASSWORD>'
假设攻击者可以把<用户名>和<密码>替换为任意字符串。在这种情况下,为用户名输入下列字符串而密码输入任意值就可以顺利绕过身份验证机制:
validuser’or‘1’= ‘1
鉴权用户的查询语句拼接如下:
SELECT * FROM db_user WHERE username='validuser' OR '1'='1' AND password='<PASSWORD>'
如果validuser记录在数据库表中存在,是一个有效的用户名,查询语句停止继续检查其他条件,不需要验证密码部分,因为用户名 validuser 判定结果是True,所有or 后面的部分不需要继续进行判定,但需要保证OR后面的SQL表达式语法正确,这样攻击者就取得了 validuser 用户的权限。类似的,攻击方可以通过构造如下密码和任意的用户名。
' OR '1'='1
查询语句拼接后如下:
SELECT * FROM db_user WHERE username='<USERNAME>' AND password='' OR '1'='1'
'1'='1判定结果恒定是True, 这样SQL查询返回数据库中所有数据。这种场景下,攻击者不需要一个有效的用户名和密码就能取得授权。
解决方法:
在SQL语句中使用占位符?来代替用户输入的值,然后再按顺序为占位符赋值。
用PreparedStatement替换Statement,即用占位符作为实参定义sql语句
合格样例:
String sqlString ="select * from db_user where username=? and password=?";
PreparedStatement stmt = connection.prepareStatement(sqlString);
stmt.setString(1,username);
stmt.setString(2,pwd);
ResultSet rs = stmt.executeQuery();
if(!rs.next())
{
throw new SecurityException("User name or password incorrect");
}
2.CERT-J面向对象,不要返回类的私有可变成员对象的引用
在一个java类中如果成员变量是可变对象就不能使用默认get方法获取这个可变变量的引用,而应使用clone,否则会造成私有状态的改变。以Date为例:
因为Date是可变对象,直接使用默认的get方法,引用了可变变量进行修改,实例中的可变变量也被修改。如果是不可变变量就不存在这样的问题,比如下图的int i。
关于java中可变对象和不可变对象的介绍可以参考下面这个链接: