1. 程式人生 > >占位符,SQL註入?

占位符,SQL註入?

switch rac () ems 控制臺 程序 bsp ras ansi

這兩天在上課時被同學拿了一段代碼問我,這段代碼有什麽問題,我看了一會說:Connection和PreparedStatement都沒關。他說不止這方面的問題,還有sql註入的問題,我就堅決的說使用了占位符不存在sql註入的問題,但是他提出了一種情況,在我看來也很有道理的情況。

pstmt = conn.prepareStatement("delete from user where user.id=?");  
pstmt.setString(1, "w");

他認為如果把代碼寫成這樣就有註入問題了

pstmt = conn.prepareStatement("delete from user where user.id=?");  
pstmt.setString(1, "w‘ or ‘2‘=‘2");  


當時我看了只能告訴他一定不存在註入問題,因為在我的想法中我一直記得的是用占位符能解決註入問題,至於怎麽解決的就不知道了,看了上面的代碼也很有道理,感覺setString後的sql語句應該是

delete from user where user.id=‘w‘ or ‘2‘=‘2‘;  

  

回到宿舍我專門寫了程序測試一下,事實證明並不想我們想的這樣,的確使用占位符不存在註入問題,所以解釋是在執行的時候把一些字符給轉義了,但這個轉義的過程是在什麽地方轉義的呢,把上面的sql語句在mysql控制臺上運行一下,查看一下數據看到所有數據都被刪除完,那只能解釋成在java程序中轉義的,於是我就去看java的源代碼,發現在java源碼中PreparedStatement只是一個接口,而且是沒有子類的接口,我就很納悶,沒實現怎麽用的?所以一定有實現的地方,去網上查了一下,jdk直提供接口,而具體實現是由數據庫廠商實現的,我們用的就是數據庫廠商實現的類。於是我就又去查mysql的jar包源碼,發現有個PreparedStatement實現了jdk中的PreparedStatement了。裏面的setString方法如下實現:

public void setString(int parameterIndex, String x) throws SQLException {
        // if the passed string is null, then set this column to null
        if (x == null) {
            setNull(parameterIndex, Types.CHAR);
        } else {
            StringBuffer buf = new StringBuffer((int) (x.length() * 1.1));
            buf.append(
‘\‘‘); int stringLength = x.length(); // // Note: buf.append(char) is _faster_ than // appending in blocks, because the block // append requires a System.arraycopy().... // go figure... // for (int i = 0; i < stringLength; ++i) { char c = x.charAt(i); switch (c) { case 0: /* Must be escaped for ‘mysql‘ */ buf.append(‘\\‘); buf.append(‘0‘); break; case ‘\n‘: /* Must be escaped for logs */ buf.append(‘\\‘); buf.append(‘n‘); break; case ‘\r‘: buf.append(‘\\‘); buf.append(‘r‘); break; case ‘\\‘: buf.append(‘\\‘); buf.append(‘\\‘); break; case ‘\‘‘: buf.append(‘\\‘); buf.append(‘\‘‘); break; case ‘"‘: /* Better safe than sorry */ if (this.usingAnsiMode) { buf.append(‘\\‘); } buf.append(‘"‘); break; case ‘\032‘: /* This gives problems on Win32 */ buf.append(‘\\‘); buf.append(‘Z‘); break; default: buf.append(c); } } buf.append(‘\‘‘); String parameterAsString = buf.toString(); byte[] parameterAsBytes = null; if (!this.isLoadDataQuery) { parameterAsBytes = StringUtils.getBytes(parameterAsString, this.charConverter, this.charEncoding, this.connection .getServerCharacterEncoding(), this.connection .parserKnowsUnicode()); } else { // Send with platform character encoding parameterAsBytes = parameterAsString.getBytes(); } setInternal(parameterIndex, parameterAsBytes); } }

到此就告一段落,可以發現在setString時最外面的單引號被轉義了,也就是說setString後的sql語句是這樣的

    delete from user where user.id=‘w\‘ or \‘2\‘=\‘2‘;  

  

而且仔細看會發現在setString中是一個字符一個字符的解析,該轉義的都已經轉義,正如他一句註釋中寫的Better safe than sorry.所以最終,占位符確實不存在註入問題

轉載於http://blog.csdn.net/yan465942872/article/details/6753957

占位符,SQL註入?