防止Java程序中的SQL注入攻击
我必须在我的java程序中添加一个语句来更新数据库表:
String insert = "INSERT INTO customer(name,address,email) VALUES('" + name + "','" + addre + "','" + email + "');";
我听说这可以通过SQL注入来利用,如:
DROP TABLE customer;
我的程序有一个Java GUI,所有的名称,地址和电子邮件值都是从Jtextfields
中检索的。 我想知道以下代码( DROP TABLE customer;
)如何被黑客添加到我的插入语句中以及如何防止这种情况。
您需要使用PreparedStatement 。 例如
String insert = "INSERT INTO customer(name,address,email) VALUES(?, ?, ?);"; PreparedStatement ps = connection.prepareStatement(insert); ps.setString(1, name); ps.setString(2, addre); ps.setString(3, email); ResultSet rs = ps.executeQuery();
这将防止注入攻击。
黑客把它放在那里的方式是你插入的String是否来自某个地方的输入 – 例如网页上的输入字段,或者应用程序中类似的表单上的输入字段。
我想知道黑客如何将这种代码(“DROP TABLE customer;”)添加到我的插入语句中
例如:
name = "'); DROP TABLE customer; --"
会将此值转换为insert :
INSERT INTO customer(name,address,email) VALUES(''); DROP TABLE customer; --"','"+addre+"','"+email+"');
我特别想知道如何防止这种情况发生
使用预处理语句和SQL参数(例如来自Matt Fellows的“被盗”):
String insert = "INSERT INTO customer(name,address,email) VALUES(?, ?, ?);"; PreparedStament ps = connection.prepareStatment(insert);
还要解析对这些变量的值,并确保它们不包含任何不允许的字符(例如名称中的“;”)。
您可以查看本文以获取相关信息! 🙂
我推荐参数化查询:
String selectStatement = "SELECT * FROM User WHERE userId = ? "; PreparedStatement prepStmt = con.prepareStatement(selectStatement); prepStmt.setString(1, userId); ResultSet rs = prepStmt.executeQuery();
攻击者只需输入类似'foo@example.com"); DROP TABLE customer;
进入email
领域即可完成。
您可以通过使用适当的JDBC语句转义来防止这种情况。
这就是你应该在字符串语句中使用问号的原因:
PreparedStatement pstmt = con.prepareStatement("UPDATE EMPLOYEES SET SALARY = ? WHERE ID = ?"); pstmt.setBigDecimal(1, 153833.00) pstmt.setInt(2, 110592)
引自这里
正如本文中所解释的那样,如果您仍在连接字符串,那么PreparedStatement
本身并没有帮助您。
例如,一名流氓攻击者仍然可以执行以下操作:
- 调用sleep函数,以便所有数据库连接都忙,从而使您的应用程序不可用
- 从数据库中提取敏感数据
- 绕过用户身份validation
并且它不仅仅是SQL,但如果您不使用绑定参数,则可能会损害JPQL和HQL:
PreparedStatement ps = connection.prepareStatement( INSERT INTO customer(name,address,email) VALUES(?, ?, ?) ); int index = 0; ps.setString(++index, name); ps.setString(++index, address); ps.setString(++index, email); ResultSet rs = ps.executeQuery();
最重要的是,在构建SQL语句时,不应该使用字符串连接。 为此目的使用专用API:
- JPA Criteria API
- jOOQ
转到PreparedStatement PreparedStatement的优点:
SQL语句的预编译和数据库端缓存可以提高整体执行速度,并能够批量重用相同的SQL语句。
通过内置转义引号和其他特殊字符自动防止SQL注入攻击。 请注意,这要求您使用任何PreparedStatement setXxx()方法来设置值