高级java开发工程师也会犯得错误,你中枪了吗。
写在前面的话:记录一下平常开发造成项目安全问题的漏洞,以免自己今后再犯错误。
1.SQL注入
SQL注入攻击即用户通过输入非法字符串,篡改原SQL语句的意图。SQL语句由用户输入条件动态组装,就存在此风险。
例如1. 屏蔽查询条件:
String userName = ctx.getAuthenticatedUserName();
String itemName = request.getParameter("itemName");
String query = "SELECT * FROM items WHERE owner = '"
+ userName + "' AND itemname = '"
+ itemName + "'";
ResultSet rs = stmt.execute(query);
如果输入的条件中为恒等式,就可能导致信息泄露,例如如果用户输入的userName参数值为“Juice’ OR ‘a’=‘a”,那么该查询语句的WHERE字句就失去了条件过滤的功能。
例如2. 篡改原SQL语句意图:
上面的例子中如果输入的userName参数值为“name’; DELETE FROM items; --”,那么原查询语句就会变成一条查询语句与一条删除操作语句,将导致在该查询动作之后,执行delete,删除items表中所有数据。
为避免SQL注入攻击,我们一般可以通过两种方式避免:
- 避免SQL语句的组装,使用“?”占位符的预编译SQL语句;
…//使用jdbc时
Connection conn = getConn();//获得连接
String sql = “select id, username, password, role from user where id=?”; //执行sql前会预编译号该条语句,无论id输入什么字符都会被当做文本来处理
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, id);
ResultSet rs=pstmt.executeUpdate();
…
…//使用mybatis框架时
select id, username, password, role from user where id=#{}
… - 如果无法避免SQL语句的组装,则应该对用户输入参数进行特殊字符处理。例如:
String id = request.getParameter(“id”);
id=id.replaceAll(“’”,”’’”)//将id中的单引号’替换成双引号’’
id=id.replaceAll(“;”,””)//将id中的分号;去除
String query = "SELECT * FROM user WHERE id =”+id
2. 资源未及时释放
系统中的一些关键资源是非常有限的,必须有效管理和使用才能保证系统的性能和稳定性,例如文件资源,网络连接资源,数据库连接资源,同步锁资源等。
资源释放需要彻底,否则可能出现内存泄露或资源无法回收的情况,例如在执行数据库操作时,我们首先获得数据库的Connection对象,然后基于此对象创建如Statement对象等数据库操作对象,那么在释放资源时,应该按创建对象的逆序关闭Statement对象和Connection对象,确保资源完全释放。
下图所示为出现该风险的问题代码:
inS为InputStream, 在finnally中对InputStream进行close时,本身可能会触发IOExceptions。 而一旦触发IOExceiponts,则之后的out(out为FileOutputStream)流将无法被成功释放资源。因此Foritfy报Unreleased Resource:Streams风险,提示可能无法正常释放FileOutputStream资源。
解决办法:
以上方案使用了一个助手函数safeClose,用以记录在尝试关闭fis流时可能发生的异常,catch住关闭流时可能引起的异常,也使后续的out流能够不会因为前面关闭流时出现异常而无法被执行到,导致后续的out流无法释放资源。
3. 空指针检查
空指针一般出现在程序员对对象的一个或多个假设前提下。如果程序明确将对象