JAVA jdbc(數據庫連接池)學習筆記(二) SQL注入


PS:今天偶然間發現了SQL的注入...所以就簡單的腦補了一下,都是一些簡單的例子...這篇寫的不怎么樣...由於自己沒有進行很深的研究...

學習內容:

1.SQL注入的概念...

  所謂SQL注入,就是通過把SQL命令插入到Web表單遞交或輸入域名或頁面請求的查詢字符串,最終達到欺騙服務器執行惡意的SQL命令,比如先前的很多影視網站泄露VIP會員密碼大多就是通過WEB表單遞交查詢字符暴出的,這類表單特別容易受到SQL注入式攻擊.當應用程序使用輸入內容來構造動態sql語句以訪問數據庫時,會發生sql注入攻擊。如果代碼使用存儲過程,而這些存儲過程作為包含未篩選的用戶輸入的字符串來傳遞,也會發生sql注入。 黑客通過SQL注入攻擊可以拿到網站數據庫的訪問權限,之后他們就可以拿到網站數據庫中所有的數據,惡意的黑客可以通過SQL注入功能篡改數據庫中的數據甚至會把數據庫中的數據毀壞掉。

2.SQL注入產生的原因...

  sql注入攻擊是利用是指利用設計上的漏洞,在目標服務器上運行Sql語句以及進行其他方式的攻擊,動態生成Sql語句時沒有對用戶輸入的數據進行驗證是Sql注入攻擊得逞的主要原因。對於java數據庫連接JDBC而言,SQL注入攻擊只對Statement有效,對PreparedStatement是無效的,這是因為PreparedStatement不允許在不同的插入時間改變查詢的邏輯結構。

3.SQL注入原理...

  SQL注射能使攻擊者繞過認證機制,完全控制遠程服務器上的數據庫。 SQL是結構化 查詢語言的簡稱,它是訪問數據庫的事實標准。目前,大多數Web應用都使用SQL數據庫來存放應用程序的數據。幾乎所有的Web應用在后台 都使用某種 SQL數據庫。跟大多數語言一樣,SQL語法允許數據庫命令和用戶數據混雜在一起的。如果開發人員不細心的話,用戶數據就有可能被解釋成命令, 這樣的 話,遠程用戶就不僅能向Web應用輸入數據,而且還可以在數據庫上執行任意命令了。

 SQL注入式攻擊的主要形式有兩種。一是直接將代碼插入到與SQL命令串聯 在一起並使得其以執行的用戶輸入變量。上面筆者舉的例子就是采用了這種方法。由於其直接與SQL語句捆綁,故也被稱為直接注入式攻擊法。二是一種間接的攻 擊方法,它將惡意代碼注入要在表中存儲或者作為原書據存儲的字符串。在存儲的字符串中會連接到一個動態的SQL命令中,以執行一些惡意的SQL代碼。注入 過程的工作方式是提前終止文本字符串,然后追加一個新的命令。如以直接注入式攻擊為例。就是在用戶輸入變量的時候,先用一個分號結束當前的語句。然后再插 入一個惡意SQL語句即可。由於插入的命令可能在執行前追加其他字符串,因此攻擊者常常用注釋標記“—”來終止注入的字符串。執行時,系統會認為此后語句 位注釋,故后續的文本將被忽略,不背編譯與執行。

4.舉例說明

  這里我只是使用簡單的語句來實現SQL的注入,只是為了讓大家簡單的看一下注入后的效果...都是一些簡單的例子,一般黑客是不可能用我這種太簡單方式來實現注入的,一般都是很復雜的東西...由於自己也不打算過深的研究這個東西,所以就上一些簡單的例子..

package JDBC_4_SQL_injection;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.sql.SQLException;
import java.sql.ResultSet;
public class injection_2 {
    static final String DB_URL="jdbc:mysql://localhost/java_mysql";
    static final String USER="root";
    static final String PAS="49681888";
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Connection cn =null;
        Statement pt=null;
        ResultSet rs=null;
        String sql="select id,name,age from test where name=''or 1 or''";//這里的or 1 or表示的是永真式...無論后面有多少語句,都會被忽略掉...
        try {
            Class.forName("com.mysql.jdbc.Driver");
            cn=DriverManager.getConnection(DB_URL,USER,PAS);
            pt=cn.createStatement();
            rs=pt.executeQuery(sql);
            //由於實現了SQL注入,因此我就能夠獲取,數據庫中所有的數據信息,這樣數據庫里的數據就造成了數據泄露...
            while(rs.next())
            {
                System.out.println(rs.toString());
                System.out.println(rs.getObject(2));
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            try {
                cn.close();
                pt.close();
                rs.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }    
        }
        
    }
}

  很簡單的實現了注入...這里使用了Statement來保存我們的因為sql語句中把1認為是true,又因為是或的關系,所以將所有的數據查詢出來了,這個就是sql注入,因為Statement會把傳遞進來的參數進行一下轉化操作,用引號包含一下,所以會出現這個問題,那么我們該怎么解決呢?有的 同學說我們可以添加一句過濾的代碼,將傳遞的參數取出單引號,這個方法是可行的的,但是這個只能解決那些使用單引號的數據庫,可能有的數據庫使用的是雙引 號包含內容,那就不行了,所以應該想一個全套的方法,那么這里我們就是用一個叫做:PreparedStatement類,這個類是Statement類 的子類..可以防止這種情況的發生...

package JDBC_4_SQL_injection;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.ResultSet;
public class injection_2 {
    static final String DB_URL="jdbc:mysql://localhost/java_mysql";
    static final String USER="root";
    static final String PAS="49681888";
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Connection cn =null;
        PreparedStatement pt=null;
        ResultSet rs=null;
        String sql="select id,name,age from test where name=?";
        try {
            Class.forName("com.mysql.jdbc.Driver");
            cn=DriverManager.getConnection(DB_URL,USER,PAS);
            pt=cn.prepareStatement(sql);
            pt.setString(1,"'or 1 or'");//在這里進行傳遞參數...
            rs=pt.executeQuery();
            while(rs.next())
            {
                System.out.println(rs.toString());
                System.out.println(rs.getObject(2));
            }//這里就不會有查詢結果了...
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            try {
                cn.close();
                pt.close();
                rs.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }    
        }
        
    }
}

正如上文所描述的,SQL 漏洞危害非常的巨大,但我相信國內很多中小站點還普遍存在着這樣的漏洞。因此建議:

    1、代碼要對輸入的參數做到充分的過濾,並盡可能得考慮極端情況
  2、錯誤信息盡可能的少,否則無關的人看不懂而有心的人就會提起興趣
  3、不要以管理員的身份運行服務器進程
  4、某些情況下,net 命令對於攻擊者而言就是“微軟牌”的木馬
  5、嚴格控制遠程登錄訪問者的來源
  6、如果可能的情況下,不是很推薦使用 Windows 作為服務器操作系統

/*另一個注入例子...
 *使用幾個查詢語句...
 * */
package JDBC_4_SQL_injection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.*;
public class injection_1 {
    static final String DB_URL="jdbc:mysql://localhost:3306/java_mysql?allowMultiQueries=true";//?allowMultiQueries=true這句話的目的是允許使用多個sql語句進行對數據庫的操作...
    static final String USER="root";
    static final String PAS="49681888";
    public static void main(String[] args) {
        // TODO Auto-generated method stub    
        String name="clearlove';delete from test;select * from test where name='clearlove";
               
        String sql=createSQL(name);
        System.out.println(sql);
        Connection cn=null;
        Statement st=null;    
        try {
            Class.forName("com.mysql.jdbc.Driver");
            cn=DriverManager.getConnection(DB_URL,USER,PAS);
            st=cn.createStatement();//實現了注入...這樣我們的數據庫信息將全部刪除掉...
            st.execute(sql);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            try {
                cn.close();
                st.close();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
        }
        
    }
    private static String createSQL(String name){
        String sql="select id, name, age from test ";
        if(name!=null && name.length()!=0){
            sql+= "where name='"+name+"'";
        }
        return sql;
    }

}

上述代碼完成了注入,直接將數據庫里面的數據進行了刪除...

/*
 * */
package JDBC_4_SQL_injection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.*;
public class injection_1 {
    static final String DB_URL="jdbc:mysql://localhost:3306/java_mysql?allowMultiQueries=true";
    static final String USER="root";
    static final String PAS="49681888";
    public static void main(String[] args) {
        // TODO Auto-generated method stub    
        String sql="select id,name,age from test where name=?";
        Connection cn=null;
        PreparedStatement st=null;    
        try {
            Class.forName("com.mysql.jdbc.Driver");
            cn=DriverManager.getConnection(DB_URL,USER,PAS);
            st=cn.prepareStatement(sql);
            st.setString(1, "clearlove';delete from test;select * from test where name='clearlove");
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            try {
                cn.close();
                st.close();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
        }
        
    }
    private static String createSQL(String name){
        String sql="select id, name, age from test ";
        if(name!=null && name.length()!=0){
            sql+= "where name='"+name+"'";
        }
        return sql;
    }

}

這里也使用了PreparedStatement來解決了這個問題的發生....

  雖然使用PreparedStatement可以避免sql的注入,但是並不意味着我們在任何時候都使用PreparedStatement,有很多時候也必須要使用Statement...這個要具體情況具體分析...

小結

SQL注入的手法相當靈活,在注入的時候會碰到很多意外的情況。能不能根據具體情況進行分析,構造巧妙的SQL語句,從而成功獲取想要的數據,是高手與“菜鳥”的根本區別。
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM