7

下面的代碼來自SAMATE Reference Dataset。我用它來測試靜態分析工具。 正如您所看到的,代碼應該通過使用清理方法以及使用預處理語句來防止SQL注入。此處準備的語句是否防止SQL注入

由於SCA工具無法知道自定義的方法,因此將不會檢測到使用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 
    { 
    } 
} 

不過我認爲,使用事先準備好的聲明中應防止注射這裏反正。我錯了嗎?

回答

3

你是對的。 prepared statement將處理「非法」SQL輸入。

allowed(...)函數是一種用戶輸入驗證的業務規則,而不是防止SQL注入。

+0

Acutally這是我自己的一個小故障。我不小心查看了錯誤項目的結果。沒關係。謝謝 – er4z0r 2010-07-08 14:32:58

1

就在準備好的聲明應該足以防止SQL注入......

然而,如果你打算寫用戶信息到「出」參數(如out.printf("Invalid username %s", name)),注意JavaScript注入。我可以輸入我的名字爲<script>alert('hi')</script>

1

它似乎阻止SQL注入。允許的()函數可以幫助你當然是正確的,但並不是最好的方法。由於你的代碼只是一個示例,我假設在現實世界中,大多數程序將允許超過5種可能的選項。

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命令。

In the nutshell Preapred語句阻止SQL注入當且僅當它們與佔位符和綁定參數一起使用時。