我的应用程序有很多使用语句编写的JDBC查询,因此容易受到SQL注入的影响。不幸的是,这个应用程序是大约10年前开发的,开发人员可能不知道准备好的声明。
我知道解决这个问题的最好方法是使用PreparedStatement,但是在整个应用程序中转换它是非常繁琐的。此外,为SQL注入编写任何类型的模式匹配都可能非常棘手,因为关键字等都是英文单词,它们也可以出现在用户输入的文本字段中。
是否有更明智的方法来避免SQL注入而不使用准备语句。如果这是一个重复的问题,请给我的链接问题,有一个很好的答案。谢谢你的帮助。
发布于 2017-11-13 20:22:02
哈哈。不幸的是,它几乎总是取决于货币和管理决定的适当,但“这是非常乏味的”一般不被认为是一个有效的工程关注-它只是一个借口,适当地重构代码。
同时,这个问题要求使用非PreparedStatement方法:简而言之,如果不能将工作卸载到库(例如准备好的语句),那么唯一的其他方法就是对每个“注入”项自己执行。无论哪种方式,都必须执行检查输入的工作。唯一的问题是它是在哪里完成的,以及是什么程序员的专业知识造就了输入验证代码。
例如,考虑一个简单的SELECT语句:
sql = "SELECT * FROM mytable WHERE id = " + untrustedVar;为了完整起见,我们可能假设注入示例中的untrustedVar是类似于1 OR 1或1; DROP TABLE mytable;的字符串,这显然会导致不必要的行为,vis- all返回给调用者的所有行,或者现在缺少的数据库表:
SELECT * FROM mytable WHERE id = 1;
DROP mytable;在这种情况下,至少可以让语言语义确保unstrustedVar是整数,也许在函数定义中是这样的:
String[] selectRowById ( int untrustedVar ) { ...或者,如果它是一个字符串,您可以使用正则表达式这样做:
Pattern valid_id_re = Pattern.compile('^\d{1,10}$'); // ensure id is between 1 and 10 billion
Matcher m = valid_id_re.matcher( unstrustedVar );
if ( ! m.matches() )
return null;但是,如果您有更长的输入没有任何语法或结构保证(例如,web表单文本区域),那么您将需要进行低级字符替换以避免潜在的不良字符。每一份声明。每个变量。每个数据库风格(PostgreSQL、Oracle、MySQL、SQLite等)。这..。是一罐虫子。
当然,这样做的好处是,如果您没有使用预先准备好的语句,而且还没有人为您的应用程序避免SQL注入攻击,那么您就别无选择。
同时,我敦促,敦促,敦促你重新考虑你对“我们不能使用事先准备好的声明,因为原因”的立场。更重要的是,正如戈德·汤普森( Gord )在下面的评论中正确地指出的那样,“无论如何,这将是一项相当大的工作,那么为什么不把它做好并完成呢?”
编辑
写完上面的内容后,我突然想到,有些人可能会认为,仅仅编写一份准备好的语句=更好的安全性。实际上,它是准备好的带有绑定参数的语句,这些参数提高了安全性。例如,人们可以这样写:
String sql = "SELECT * FROM mytable WHERE id = " + untrustedVar;
PreparedStatment pstmt = dbh.prepareStatement( sql );
return pstmt.executeQuery();此时,您所做的不过是准备一条已经注入恶意代码的语句。相反,考虑参数的实际绑定:
String sql = "SELECT * FROM mytable WHERE id = ?"; // Raw string; never touched by "tainted" variable
PreparedStatment pstmt = dbh.prepareStatement( sql );
pstmt.setObject(1, p); // Perform the actual binding.
return pstmt.executeQuery();后一个例子做了两件事。它首先创建一个已知的安全格式,并将那个发送到DB进行准备。然后,在DB返回准备语句的句柄后,我们是否绑定变量,并最终执行语句。
https://stackoverflow.com/questions/47272504
复制相似问题