From: Barry Lind Date: Tue, 22 Jul 2003 05:17:09 +0000 (+0000) Subject: Fix to prevent SQL injection attacks for code calling setObject(int,Object,int) X-Git-Tag: REL7_4_BETA1~170 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0a73f69cb4842f46c1a080b3375b0f268ba1e5de;p=postgresql Fix to prevent SQL injection attacks for code calling setObject(int,Object,int) where Object is a user supplied String and the type is a numeric type (i.e. INTEGER,LONG,etc). Also applied a patch from Kim Ho that fixes compile problems under jdk1.2 Modified Files: jdbc/org/postgresql/Driver.java.in jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java --- diff --git a/src/interfaces/jdbc/org/postgresql/Driver.java.in b/src/interfaces/jdbc/org/postgresql/Driver.java.in index de064bb8cf..16f0d99c06 100644 --- a/src/interfaces/jdbc/org/postgresql/Driver.java.in +++ b/src/interfaces/jdbc/org/postgresql/Driver.java.in @@ -6,7 +6,7 @@ * Copyright (c) 2003, PostgreSQL Global Development Group * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/Attic/Driver.java.in,v 1.32 2003/07/21 20:48:31 barry Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/Attic/Driver.java.in,v 1.33 2003/07/22 05:17:09 barry Exp $ * *------------------------------------------------------------------------- */ @@ -503,6 +503,6 @@ public class Driver implements java.sql.Driver //The build number should be incremented for every new build - private static int m_buildNumber = 206; + private static int m_buildNumber = 207; } diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java b/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java index 9a5b5203a1..c8af729b9a 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java @@ -25,7 +25,7 @@ import java.sql.Timestamp; import java.sql.Types; import java.util.Vector; -/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Statement.java,v 1.27 2003/07/09 05:12:04 barry Exp $ +/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Statement.java,v 1.28 2003/07/22 05:17:09 barry Exp $ * This class defines methods of the jdbc1 specification. This class is * extended by org.postgresql.jdbc2.AbstractJdbc2Statement which adds the jdbc2 * methods. The real Statement class (for jdbc1) is org.postgresql.jdbc1.Jdbc1Statement @@ -1035,22 +1035,37 @@ public abstract class AbstractJdbc1Statement implements BaseStatement { sbuf.setLength(0); sbuf.ensureCapacity(x.length() + (int)(x.length() / 10)); - int i; - sbuf.append('\''); - for (i = 0 ; i < x.length() ; ++i) - { - char c = x.charAt(i); - if (c == '\\' || c == '\'') - sbuf.append((char)'\\'); - sbuf.append(c); - } + escapeString(x, sbuf); sbuf.append('\''); bind(parameterIndex, sbuf.toString(), type); } } } + private String escapeString(String p_input) { + // use the shared buffer object. Should never clash but this makes + // us thread safe! + synchronized (sbuf) + { + sbuf.setLength(0); + sbuf.ensureCapacity(p_input.length()); + escapeString(p_input, sbuf); + return sbuf.toString(); + } + } + + private void escapeString(String p_input, StringBuffer p_output) { + for (int i = 0 ; i < p_input.length() ; ++i) + { + char c = p_input.charAt(i); + if (c == '\\' || c == '\'') + p_output.append((char)'\\'); + p_output.append(c); + } + } + + /* * Set a parameter to a Java array of bytes. The driver converts this * to a SQL VARBINARY or LONGVARBINARY (depending on the argument's @@ -1467,7 +1482,7 @@ public abstract class AbstractJdbc1Statement implements BaseStatement if (x instanceof Boolean) bind(parameterIndex,((Boolean)x).booleanValue() ? "1" :"0", PG_BOOLEAN); else - bind(parameterIndex, x.toString(), PG_INTEGER); + bind(parameterIndex, escapeString(x.toString()), PG_INTEGER); break; case Types.TINYINT: case Types.SMALLINT: @@ -1480,7 +1495,7 @@ public abstract class AbstractJdbc1Statement implements BaseStatement if (x instanceof Boolean) bind(parameterIndex, ((Boolean)x).booleanValue() ? "1" : "0", PG_BOOLEAN); else - bind(parameterIndex, x.toString(), PG_NUMERIC); + bind(parameterIndex, escapeString(x.toString()), PG_NUMERIC); break; case Types.CHAR: case Types.VARCHAR: @@ -1913,15 +1928,12 @@ public abstract class AbstractJdbc1Statement implements BaseStatement } /* - * There are a lot of setXXX classes which all basically do - * the same thing. We need a method which actually does the - * set for us. - * - * @param paramIndex the index into the inString - * @param s a string to be stored - * @exception SQLException if something goes wrong + * Note if s is a String it should be escaped by the caller to avoid SQL + * injection attacks. It is not done here for efficency reasons as + * most calls to this method do not require escaping as the source + * of the string is known safe (i.e. Integer.toString()) */ - protected void bind(int paramIndex, Object s, String type) throws SQLException + private void bind(int paramIndex, Object s, String type) throws SQLException { if (paramIndex < 1 || paramIndex > m_binds.length) throw new PSQLException("postgresql.prep.range"); @@ -2072,7 +2084,9 @@ public abstract class AbstractJdbc1Statement implements BaseStatement if (timezoneLocation>7 && timezoneLocation+3 == s.length()) { timezone = Integer.parseInt(s.substring(timezoneLocation+1,s.length())); - localoffset = java.util.Calendar.getInstance().getTimeZone().getOffset(millis); + localoffset = java.util.Calendar.getInstance().getTimeZone().getRawOffset(); + if (java.util.Calendar.getInstance().getTimeZone().inDaylightTime(new java.sql.Date(millis))) + localoffset += 60*60*1000; if (s.charAt(timezoneLocation)=='+') timezone*=-1; } @@ -2101,7 +2115,9 @@ public abstract class AbstractJdbc1Statement implements BaseStatement if (timezoneLocation != -1 && timezoneLocation+3 == s.length()) { timezone = Integer.parseInt(s.substring(timezoneLocation+1,s.length())); - localoffset = java.util.Calendar.getInstance().getTimeZone().getOffset(millis); + localoffset = java.util.Calendar.getInstance().getTimeZone().getRawOffset(); + if (java.util.Calendar.getInstance().getTimeZone().inDaylightTime(new java.sql.Date(millis))) + localoffset += 60*60*1000; if (s.charAt(timezoneLocation)=='+') timezone*=-1; } @@ -2146,7 +2162,9 @@ public abstract class AbstractJdbc1Statement implements BaseStatement if (timezoneLocation>8 && timezoneLocation+3 == s.length()) { timezone = Integer.parseInt(s.substring(timezoneLocation+1,s.length())); - localoffset = java.util.Calendar.getInstance().getTimeZone().getOffset(millis); + localoffset = java.util.Calendar.getInstance().getTimeZone().getRawOffset(); + if (java.util.Calendar.getInstance().getTimeZone().inDaylightTime(new java.sql.Date(millis))) + localoffset += 60*60*1000; if (s.charAt(timezoneLocation)=='+') timezone*=-1; }