為啥jdbc問號佔位符可以防注入
最近幾天探討一下關於sql注入的問題,以前林老師也講過,現在總結一下,
其實,like是會注入的,也不建議用,用佔位符實際查詢效果不是like本身的意思,相當全匹配。
建議使用instr()函式,本文主要記錄一下處理防止注入的原始碼,為什麼用?可以防注入,而拼接的sql可以注入。
先看下面用佔位符來查詢的一句話
String sql = "select * from administrator where adminname=?"; psm = con.prepareStatement(sql);
String s_name ="zhangsan' or '1'='1"; psm.setString(1, s_name);
假設資料庫表中並沒有zhangsan這個使用者名稱,
用plsql執行sql語句,可以查出來所有的使用者名稱,但是在Java中並沒有查出任何資料,這是為什麼呢?
首先,setString()的原始碼中只有方法名字,並沒有任何過程性處理,
那麼答案肯定出現在Java到資料庫這個過程中,也就是mysql和oracle驅動包中,在mysql驅動包中,PreparedStatement繼承並實現了jdk中的setString方法,翻看一下原始碼,主要是做了轉義處理,
也就是原因在於資料庫廠商幫你解決了這個問題,下面就看看這個方法的具體實現:
public void setString(int parameterIndex, String x) throws SQLException { if(x == null) { setNull(parameterIndex, 1); } else { checkClosed(); int stringLength = x.length(); if(connection.isNoBackslashEscapesSet()) { boolean needsHexEscape = isEscapeNeededForString(x, stringLength); if(!needsHexEscape) { byte parameterAsBytes[] = null; StringBuffer quotedString = new StringBuffer(x.length() + 2); quotedString.append('\''); quotedString.append(x); quotedString.append('\''); if(!isLoadDataQuery) parameterAsBytes = StringUtils.getBytes(quotedString.toString(), charConverter, charEncoding, connection.getServerCharacterEncoding(), connection.parserKnowsUnicode()); else parameterAsBytes = quotedString.toString().getBytes(); setInternal(parameterIndex, parameterAsBytes); } else { byte parameterAsBytes[] = null; if(!isLoadDataQuery) parameterAsBytes = StringUtils.getBytes(x, charConverter, charEncoding, connection.getServerCharacterEncoding(), connection.parserKnowsUnicode()); else parameterAsBytes = x.getBytes(); setBytes(parameterIndex, parameterAsBytes); } return; } String parameterAsString = x; boolean needsQuoted = true; if(isLoadDataQuery || isEscapeNeededForString(x, stringLength)) { needsQuoted = false; StringBuffer buf = new StringBuffer((int)((double)x.length() * 1.1000000000000001D)); buf.append('\''); for(int i = 0; i < stringLength; i++) { char c = x.charAt(i); switch(c) { case 0: // '\0' buf.append('\\'); buf.append('0'); break; case 10: // '\n' buf.append('\\'); buf.append('n'); break; case 13: // '\r' buf.append('\\'); buf.append('r'); break; case 92: // '\\' buf.append('\\'); buf.append('\\'); break; case 39: // '\'' buf.append('\\'); buf.append('\''); break; case 34: // '"' if(usingAnsiMode) buf.append('\\'); buf.append('"'); break; case 26: // '\032' buf.append('\\'); buf.append('Z'); break; default: buf.append(c); break; } } buf.append('\''); parameterAsString = buf.toString(); } byte parameterAsBytes[] = null; if(!isLoadDataQuery) { if(needsQuoted) parameterAsBytes = StringUtils.getBytesWrapped(parameterAsString, '\'', '\'', charConverter, charEncoding, connection.getServerCharacterEncoding(), connection.parserKnowsUnicode()); else parameterAsBytes = StringUtils.getBytes(parameterAsString, charConverter, charEncoding, connection.getServerCharacterEncoding(), connection.parserKnowsUnicode()); } else { parameterAsBytes = parameterAsString.getBytes(); } setInternal(parameterIndex, parameterAsBytes); parameterTypes[(parameterIndex - 1) + getParameterIndexOffset()] = 12; } }