Java Web漏洞审计:SQL注入(SQLi)

在Java应用程序中,与数据库交互通常使用JDBC(Java Database Connectivity)。在JDBC中,有两种执行SQL语句的方式,分别是Statement和PreparedStatement。

图片[1]-Java Web漏洞审计:SQL注入(SQLi)-山海云端论坛

准备

数据库

<code>CREATE DATABASE IF NOT EXISTS testsqli; CREATE TABLE IF NOT EXISTS `user` ( `id` int unsigned AUTO_INCREMENT, `username` varchar(100) NOT NULL, `password` varchar(100) NOT NULL, PRIMARY KEY (`id`) ) CHARSET=utf8; INSERT INTO user (id, username, password) VALUES (1, "Bob", "12345678"); INSERT INTO user (id, username, password) VALUES (2, "Alice", "1qaz@WSX"); INSERT INTO user (id, username, password) VALUES (3, "admin", "admin123");</code>

pom.xml

<code><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.13</version> </dependency></code>

Statement

SQL语句为:

<code>String sql = "SELECT * FROM user WHERE username = '" + username + "' AND password = '" + password + "'";</code>

当传入的数值为正常数值时,如:username = admin, password = admin123,若存在当前用户名及密码的账户,则会返回数据。

图片[2]-Java Web漏洞审计:SQL注入(SQLi)-山海云端论坛

然而,当我们传入admin' OR 1=1#时,改变了SQL语义,1=1为恒真,并注释掉SQL语句后面的内容,因此表达式会返回所有结果。这意味着在知道用户名存在的情况下,即可用admin' and 1=1#进行登录。

图片[3]-Java Web漏洞审计:SQL注入(SQLi)-山海云端论坛

显然,JDBC使用Statement的方式进行数据库操作是很危险的,因此一般开发人员会使用PreparedStatement做预编译。

PreparedStatement

与Statement的区别在于,PreparedStatement会对SQL语句进行预编译。无论最后输入的是什么,预编译的语句只是作为字符串来执行。因此,在正确使用PreparedStatement的前提下,解决了注入问题。

测试代码

<code>public static void select(String username, String password) throws Exception { Connection connection = JdbcSqli.connector(); String sql = "SELECT * FROM user WHERE username = ? AND password = ?"; PreparedStatement preparedStatement = connection.prepareStatement(sql); preparedStatement.setString(1, username); preparedStatement.setString(2, password); ResultSet resultSet = preparedStatement.executeQuery(); while (resultSet.next()) { System.out.println("id=" + resultSet.getObject("id") + ", username=" + resultSet.getObject("username") + ", password=" + resultSet.getObject("password")); } preparedStatement.close(); connection.close(); }</code>

在测试代码中,通过使用PreparedStatement的方式进行数据库操作,有效地防止了SQL注入。PreparedStatement的防御原理在于使用?作为占位符,预编译后的语句已经确定整个SQL语句的结构,因此即使攻击者传入SQL语句也不会被数据库解析。

PreparedStatement 防御SQL原理

通过查看PreparedStatement的源代码,我们可以了解其防御SQL注入的原理。

PreparedStatement在设置参数时,会对传入的字符串进行处理,将特殊字符进行转义。这样一来,即使用户输入的字符串中包含了SQL语句的关键字符,也不会对SQL语句造成破坏。

总结

虽然使用PreparedStatement可以有效防御大部分SQL注入攻击,但在某些情况下仍然存在注入的风险。例如,当开发人员拼接用户输入、使用In语句、Like语句或Order by语句时,都有可能导致SQL注入漏洞的产生。因此,在编写代码时,务必谨慎处理用户输入,避免造成安全隐患。

© 版权声明
THE END
喜欢就支持一下吧
点赞13 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容