these two days in class by classmate took a piece of code asked me, this code has what problem, I read a will say: Connection and PreparedStatement are not closed. He said more than that, as well as SQL injection, I was adamant that there was no SQL injection in place of the placeholder, but he raised a situation that seemed to me to be a reasonable point.
pstmt = conn.preparestatement ("Delete from user where user.id=?");
pstmt.setstring (1, "w");
he thinks that if you write the code, there's an injection problem.
pstmt = conn.preparestatement ("Delete from user where user.id=?"); Pstmt.setstring (1, "w ' or ' 2 ' = ' 2");
At that time I watched only to tell him there must be no injection problem, because in my mind I always remember is to use the placeholder can solve the injection problem, as to how to solve the don't know, see the above code is also very reasonable, feel setstring after the SQL statement should be
Delete from user where user.id= ' W ' or ' 2 ' = ' 2 ';
back to the dorm I specifically wrote a program test, it turns out that we do not want to think of this, it is true that there is no injection problem with the placeholder, so the explanation is to escape some characters at the time of execution, but where is this escaping process escaped? The above SQL statements run on the MySQL console, look at the data to see all the data are deleted, that can only be explained in the Java program to transfer the meaning, so I went to see Java source code, found in Java source PreparedStatement is just an interface, And there is no sub-class interface, I am very puzzled, did not realize how to use it? So there must be an implementation of the place, to check the Internet, JDK directly provide interface, and the implementation is implemented by the database vendors, we use is the database vendor implementation of the class. So I went to check the MySQL jar package source code, found that there is a preparedstatement to achieve the JDK preparedstatement. The SetString method is implemented as follows:
public void setString (int parameterindex, string x) throws SQLException {//If the passed String is null and then set this CO Lumn to nullif (x = = null) {SetNull (Parameterindex, Types.char);} else {StringBuffer buf = new StringBuffer ((int) (x.lengt H () * 1.1)); Buf.append (' \ '); int stringlength = X.length ();////Note:buf.append (char) is _faster_ than//appending in Blo CKS, 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 is escaped for ' MySQL ' */buf.append (' \ \ '); Buf.append (' 0 '); Break;case ' \ n ':/* must is escaped for logs */buf.append (' \ \ '); Buf.append ' \ R ': break;case (' \ \ '); 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 encodingparameterasbytes = Parameterasstring.getbytes ();} Setinternal (Parameterindex, parameterasbytes);}}
at this time, you can find that the outermost single quote is escaped at setstring, which means that the SQL statement after setstring
Delete from user where user.id=\ ' W ' or ' 2 ' = ' 2\ ';
and look closely will find in the setstring is a character parsing, the escape has escaped, as he wrote in a note better safe than sorry. So eventually, the placeholder does not have an injection problem.
placeholder, SQL injection?