2

我正在尝试在将数据插入数据库(POSTGRESQL)之前验证数据。使用 Apache Commons Validator 可以轻松验证与电子邮件、邮政编码等对应的数据。但在名称的情况下,我使用了这个:

^[a-zA-Z][ a-zA-Z]{1-30}$

这可以防止将任何特殊字符添加为名称,但无法防止用户添加DROP or GRANT为名称。在我使用时PreparedStatement,我认为这不会成为问题,但现在要求 SQL 关键字不应进入数据库,因为它可能导致二阶 SQL 注入。

我曾想过将所有 SQL 关键字列入黑名单(当然,这会阻止 Huge Grant 登录我们的网站。:P)但似乎有超过 64 个关键字。这(SQL 关键字的黑名单过滤数据)是防止二阶 SQL 注入的正确方法吗?我有哪些选择?

我正在使用这段代码:

String sql="INSERT INTO users (username, password, name) VALUES (?,?,?);";
        try{
            conn=SomeStaticClass.createConnection();
            ps=conn.prepareStatement(sql);
            ps.setString(1, dataBean.getUsername());
            ps.setString(2, dataBean.getPassword());
            ps.setString(3, dataBean.getName());
            ps.execute();
        }catch(SQLException e){
            e.printStackTrace()
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            try{
                if(ps!=null){
                    ps.close();
                }
                conn.close();
            }catch(SQLException e){
                e.printStackTrace();
            }
        }
4

4 回答 4

2

对于这种情况,这是正确的方法吗?

不。

当您通过连接字符串来组装 SQL 查询时,就会发生 SQL 注入。

防止 SQL 注入的“最佳实践”方法是使用PreparedStatement具有参数占位符的常量 SQL 查询。然后使用准备好的语句set方法为每个占位符参数设置值。这种方法将保证任何包含 SQL 关键字的“讨厌的”字符串参数都将被解释为文字字符串。


更新-PreparedStatements一致使用也应该防止二阶攻击......假设你指的是这样的东西:

http://download.oracle.com/oll/tutorials/SQLInjection/html/lesson1/les01_tm_attacks2.htm

你只需要确保你没有从任何可能被污染的东西中构建 SQL 查询字符串。如果您使用占位符处理任何可能受到污染的数据,那么它来自哪里并不重要。

(黑名单 SQL 关键字将有助于将垃圾排除在您的数据库之外。但正如您所提到的,它可能会损坏合法数据并影响您系统的可用性。我不会这样做。最好依靠 good程序员纪律......和彻底的代码审查。)

于 2012-12-06T06:42:53.687 回答
1

仅当您将关键字存储在数据库中,然后以不安全的方式使用它们时,才会发生二阶注入。如果您使用准备好的语句并且它们被正确参数化,它将不会发生。思科对 SQL 注入的理解有一个很好的总结:

http://www.cisco.com/web/about/security/intelligence/sql_injection.html

除了您的“Grant”示例之外,还有许多诸如 IF、BY、IS、IN、TO 等会在英语/名称中非常常见。

于 2012-12-06T06:49:01.360 回答
1

确保数据库中的所有数据都可以与任何脚本语言(如 SQL 或 HTML)一起使用,即使不是不可能,也是非常困难的,而且将来没有适当的转义。在你现在如何使用这些字符之前,不可能区分“安全”和“不安全”字符。

试图在将所有数据插入数据库之前对其进行转义和清理可能会让您相信数据库中用户生成的数据是“安全的”,这是一种非常危险的信念。只有知道如何使用数据才能知道数据是否安全,并且只有在实际使用数据时才能知道数据是否安全(因为数据库中的数据可以存在很长时间)。

避免此类问题的最佳策略是在实际使用所有数据时始终对其进行转义,或者像您一样使用 PreparedStatement,在 html 中使用它们时正确转义它们,当您将它们插入电子邮件时转义它们等。等等

我在这个答案中举了一些例子:

如何使用 OWASP HTML Sanitizer 允许特定字符?

于 2012-12-06T10:14:47.193 回答
0

除了使用 PreparedStatement 之外,您还必须在您的网页上检查用户提供的输入。

所以现在你有 2 个不同的检查。1. 在您的网页上,这将减少处理时间。2. 如果某些内容通过了您的初始检查,那么preparedstatement 将确保您的查询被正确解析。

例如,用户正在搜索某个项目..

用户输入是

' OR ITEM in (Select ITEM from SOME_TABLE) OR ITEM = ''

你正在构建你的 SQL,通过连接字符串,然后它将使 SQL 命令为

Select * from TABLE_X WHERE ITEM = '' OR ITEM in (Select ITEM from SOME_TABLE) OR ITEM = ''

所以你的数据库被黑了,但在其他情况下 PreparedStatement 它将解析你的查询并且不会让用户修改 SQL ......

于 2012-12-06T06:53:48.920 回答