代码之家  ›  专栏  ›  技术社区  ›  er4z0r

准备好的语句是否阻止此处的SQL注入?

  •  7
  • er4z0r  · 技术社区  · 14 年前

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

    由于SCA工具不知道自定义的sanitzation方法,因此不会检测到 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 回复  |  直到 11 年前
        1
  •  3
  •   MicSim    14 年前

    你说得对。这个 prepared statement 将处理“非法”的SQL输入。

    这个 allowed(...) 函数是一种根据业务规则进行的用户输入验证,而不是为了防止SQL注入。

        2
  •  3
  •   Noname    11 年前

    是的,这里准备的语句将阻止SQL注入。这是因为您使用的是占位符(?)在查询中。这是一个重要的占位符。

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

    PreparedStatement ps=conn.PrepareStatement(“从名字类似“+名字”的用户中选择*);

    上面的语句即使是准备好的语句也不会阻止SQL注入

    但是,下面准备的语句可以很好地防止SQL注入。

    PreparedStatement ps=conn.PrepareStatement(“select*from users where firstname like?”);

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

    这意味着像(a'或'1'='1)这样的恶意用户输入可以更改第一条语句中的查询。但是,第二个查询(因为它是预编译的)将把恶意用户输入视为数据而不是SQL命令。

    简而言之,prepred语句仅在与占位符和绑定参数一起使用时才防止SQL注入。

        3
  •  1
  •   tim_yates    14 年前

    仅仅准备好的语句就足以防止SQL注入…

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

        4
  •  1
  •   MJB    14 年前

    它似乎可以防止SQL注入。当然,您正确地认为allowed()函数有帮助,但它不是首选的方法。由于您的代码只是一个示例,我假设在现实世界中,大多数程序都允许5个以上的选项。