SQLException:仅使用PreparedStatement的参数索引1无效

时间:2016-10-28 09:10:51

标签: java sql-server-2012 prepared-statement sql-injection jtds

我有一个带有Tomcat8 + SQL Server2012的webapp(JSP / Servlet) JDBC驱动程序类型4:JTDS旧版本1.2.5(http://jtds.sourceforge.net/

我更改了这种查询,添加了Prepared Statement(服务器分页)

    Sting DDXsql = "SELECT '?' *, ( DDX_RECORD_COUNT / '?' + 1 ) AS DDX_PAGE_COUNT 
FROM 
( SELECT '?' * 
FROM ( SELECT '?' *, 
             (SELECT COUNT(*) " + "FROM " 
          + session.getAttribute("DatabaseName") + ".G1_grid " 
          + sqlFrom 
          + sqlWhere + " "    
            + " )  AS DDX_RECORD_COUNT " 
        + "FROM " + session.getAttribute("DatabaseName") + ".G1_grid " 
        + sqlFrom 
        + sqlWhere + " " 
        +    " ORDER BY '?' '?' , '?' '?' ) AS TMP1 ORDER 
          BY '?' '?', '?' '?') AS r ORDER BY '?' '?', '?'  '?'";

参数:

String top1 = DBManager.getTOP(request, "TOP " + Integer.valueOf((String)ResourceManager.findData("pageSize", request)));
                Integer pagesizeInt = Integer.valueOf((String)ResourceManager.findData("pageSize", request));
                String top2 = DBManager.getTOP(request, "TOP " + Integer.valueOf((String)ResourceManager.findData("ddxrecordcount", request))); 
                String top3= DBManager.getTOP(request, "TOP " + Integer.valueOf((String)ResourceManager.findData("toRange", request)));
                String notSortStr = (String)ResourceManager.findData("notSort", request);
                Object[] values = new Object[] {
                top1,               
                pagesizeInt,
                top2,           
                top3,
                SortKey,
                Sort,
                TotalSortKey,
                Sort,
                SortKey,
                notSortStr,
                TotalSortKey ,          
                notSortStr,     
                SortKey,
                Sort,
                TotalSortKey,
                Sort
                };

之前,我没有使用PreparedStatement我有这种查询(替换"?"使用Object数组值,不使用StringEscapeUtils):

    String DDXsql = "SELECT " + 
DBManager.getTOP(request, "TOP " 
+ Integer.valueOf(StringEscapeUtils.escapeSql((String)ResourceManager.findData("pageSize", request)))) + " *, 
( DDX_RECORD_COUNT / " + Integer.valueOf(StringEscapeUtils.escapeSql((String)ResourceManager.findData("pageSize", request))) + " + 1 ) AS DDX_PAGE_COUNT FROM 
( SELECT " 
+ DBManager.getTOP(request, "TOP "
 + Integer.valueOf(StringEscapeUtils.escapeSql((String)ResourceManager.findData("ddxrecordcount", request)))) 
+ " * FROM ( SELECT " + DBManager.getTOP(request, "TOP " + Integer.valueOf(StringEscapeUtils.escapeSql((String)ResourceManager.findData("toRange", request)))) 
+ " *, (SELECT COUNT(*) " 
+ "FROM " + session.getAttribute("DatabaseName") + ".G1_grid " + sqlFrom + sqlWhere + " " + " )  AS DDX_RECORD_COUNT " 
+ "FROM " + session.getAttribute("DatabaseName") 
+ ".G1_grid " + sqlFrom + sqlWhere + " " + " ORDER BY "
 + StringEscapeUtils.escapeSql(SortKey) + " " + StringEscapeUtils.escapeSql(Sort) + ", " 
+ StringEscapeUtils.escapeSql(TotalSortKey) + " " 
+ StringEscapeUtils.escapeSql(Sort) + ") AS TMP1 ORDER BY "
 + StringEscapeUtils.escapeSql(SortKey) + " " 
+ StringEscapeUtils.escapeSql((String)ResourceManager.findData("notSort", request)) 
+ ", " + StringEscapeUtils.escapeSql(TotalSortKey) + " " 
+ StringEscapeUtils.escapeSql((String)ResourceManager.findData("notSort", request)) + " ) AS r ORDER BY " 
+ StringEscapeUtils.escapeSql(SortKey) + " " 
+ StringEscapeUtils.escapeSql(Sort) + ", " 
+ StringEscapeUtils.escapeSql(TotalSortKey) 
+ " " + StringEscapeUtils.escapeSql(Sort) + " ";

最后一个查询运行没有错误,此查询的System.out例如:

SELECT TOP 20 *, ( DDX_RECORD_COUNT / 20 + 1 ) AS DDX_PAGE_COUNT 
FROM 
( SELECT TOP 20 * FROM 
               ( SELECT TOP 20 *, 
                   (SELECT COUNT(*) 
                     FROM SuiteMA_DIP.dbo.G1_grid  
                  WHERE 1 = 1   )  AS DDX_RECORD_COUNT 
                FROM SuiteMA_DIP.dbo.G1_grid  WHERE 1 = 0   ORDER BY DATA_ISCRIZIONE_ORDER DESC, SOGGETTO_RILEVANTE_PAID DESC) AS TMP1 ORDER BY DATA_ISCRIZIONE_ORDER ASC, SOGGETTO_RILEVANTE_PAID ASC ) AS r ORDER BY DATA_ISCRIZIONE_ORDER DESC, SOGGETTO_RILEVANTE_PAID DESC 

但是当我用preparedStatement运行sql:

java.sql.SQLException: Invalid parameter index 1.
    at net.sourceforge.jtds.jdbc.JtdsPreparedStatement.getParameter(JtdsPreparedStatement.java:340)
    at net.sourceforge.jtds.jdbc.JtdsPreparedStatement.setParameter(JtdsPreparedStatement.java:409)
    at net.sourceforge.jtds.jdbc.JtdsPreparedStatement.setObjectBase(JtdsPreparedStatement.java:395)
    at net.sourceforge.jtds.jdbc.JtdsPreparedStatement.setObject(JtdsPreparedStatement.java:667)
    at org.apache.tomcat.dbcp.dbcp2.DelegatingPreparedStatement.setObject(DelegatingPreparedStatement.java:188)
    at org.apache.tomcat.dbcp.dbcp2.DelegatingPreparedStatement.setObject(DelegatingPreparedStatement.java:188)
    at it.netbureau.jfx.db.SQLDBManager.execSQL(SQLDBManager.java:57)
    at it.netbureau.jfx.db.SQLDBManager.execSQL(SQLDBManager.java:78)
    at org.apache.jsp.G1.select_jsp._jspService(select_jsp.java:691)

java方法执行查询:

class jfx.db.SQLDBManager.execSQL:

public Object execSQL(PreparedStatement stmt, Object values[], String xmlId)
        throws SQLException
    {
        Object result = null;
        if(stmt == null)
            return null;
        try
        {
            for(int i = 0; i < values.length; i++)
                if(values[i] == null)
                    stmt.setNull(i + 1, 4);
                else
                    stmt.setObject(i + 1, values[i]); <--this give exception!

            if(stmt.execute())                  result = transform(stmt.getResultSet(), xmlId);
        }
        catch(SQLException ex)
        {
            rollback();
            throw ex;
        }
        return result;
    }

出了什么问题?

非常感谢

拉​​吉

1 个答案:

答案 0 :(得分:6)

您的查询不包含任何参数,'?'只是一个带有问号的文字字符串,它不是参数。

您也无法参数化对象名称,例如列名和子句(例如TOP 20),因此,即使您将其更改为 - 例如 - order by ?, ...,它也不会#39; t work,因为你要按字符串值排序(对于所有行都是相同的,所以你实际上根本不会排序)。

要执行您想要执行的操作,您需要将列名(和其他子句)连接到查询字符串中。这也意味着您可以自己打开SQL注入:请务必仔细检查值(例如,针对允许值的白名单)。