预准备语句是否在此处阻止SQL注入

时间:2010-07-08 14:11:19

标签: java security sql-injection static-analysis prepared-statement

以下代码来自SAMATE Reference Dataset。我用它来测试静态分析工具。 正如您所看到的,代码应该通过使用清理方法以及使用预准备语句来阻止SQL注入。

由于SCA工具无法知道自定义santitzation方法,因此不会检测到allowed方法用于防止注入。

public class SQLInjection_good_089 extends HttpServlet
{
    private static final long serialVersionUID = 1L;

    public SQLInjection_good_089()
    {
        super();
    }

    // Table of allowed names to use
    final String allowed_names[] = { "Mickael", "Mary", 
            "Peter", "Laura", "John"};

    // Function to check if the current name takes part of the allowed ones
    public boolean allowed( String in )
    {
        boolean bool = false;

        for( int i = 0; i < 5; i++ )
        {
            if( in.equals( allowed_names[i] ) )
            {
                // the current name is allowed to use
                bool = true;
                break;
            }
        }
        return bool;
    }

    // Method which will be called to handle HTTP GET requests
    protected void doGet( HttpServletRequest req, HttpServletResponse resp )
        throws ServletException, IOException
    {
        // Initialize the output stream
        resp.setContentType("text/html");
        ServletOutputStream out = resp.getOutputStream();
        out.println("<HTML><BODY><blockquote><pre>");
        Connection conn = null;

        // Get the parameter "name" from the data provided by the user
        String name = req.getParameter( "name" );

        if ( (name != null) && (allowed(name) == true) )
        {
            try
            {
                // Set the context factory to use to create the initial context
                System.setProperty (Context.INITIAL_CONTEXT_FACTORY, "your.ContextFactory");

                // Create the initial context and use it to lookup the data source
                InitialContext ic = new InitialContext ();
                DataSource dataSrc = (DataSource) ic.lookup ("java:comp/env/jdbc:/mydb");

                // Create a connection to the SQL database from the data source
                conn = dataSrc.getConnection();

                // Send a SQL request to the database
                PreparedStatement ps = conn.prepareStatement( "SELECT * FROM users WHERE firstname LIKE ?" );
                // replace the first parameter by name
                ps.setString(1, name);
                ps.executeQuery();
            }
            catch( NamingException e )
            {
                out.println( "Naming exception");
            }
            catch( SQLException e )
            {
                out.println( "SQL exception");
            }
            finally
            {
                try
                {
                    if (conn != null)
                        conn.close ();
                }
                catch (SQLException se)
                {
                    out.println("SQL Exception");
                }
            }
        }
        else
            return;

        out.println( "</pre></blockquote></body></html>" );
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
    {
    }
}

尽管如此,我认为使用预先准备好的声明应该可以防止注入此处。我错了吗?

4 个答案:

答案 0 :(得分:3)

你是对的。 prepared statement将处理'非法'SQL输入。

allowed(...) 函数是业务规则方面的一种用户输入验证,而不是防止SQL注入。

答案 1 :(得分:3)

是这里准备好的语句将阻止sql注入。这是因为您在查询中使用占位符(?)。这是占位符,这里需要注意。

以下是准备好的陈述的2个例子。第一个不会阻止sql注入。

PreparedStatement ps = conn.prepareStatement(“SELECT * FROM users WHERE firstname LIKE”+ name);

以上语句即使是准备语句也不会阻止sql注入

但是下面编写的语句可以防止sql注入。

PreparedStatement ps = conn.prepareStatement(“SELECT * FROM users WHERE firstname LIKE?”);

第一个和第二个语句的区别是,第一种情况下的查询是在运行时动态编译的,但在第二种情况下是预编译的。

这意味着像(a'or'1'='1)这样的恶意用户输入可以在第一个语句中改变查询。但是,自预编译以来的第二个查询将恶意用户输入视为数据,而不是sql命令。

简而言之,当且仅当它们与占位符和绑定参数一起使用时,Preapred语句才会阻止SQL注入。

答案 2 :(得分:1)

准备好的语句应该足以阻止SQL注入......

但是,如果您打算将用户消息写入'out'参数(例如out.printf( "Invalid username %s", name )),请注意javascript注入。我可以输入我的姓名<script>alert('hi')</script>

答案 3 :(得分:1)

似乎阻止了SQL注入。你当然是正确的,allow()函数有帮助,但不完全是首选的方法。由于您的代码只是一个示例,我认为在现实世界中大多数程序将允许超过5种可能的选项。