/* * Copyright 2009-2012 Michael Dalton * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jtaint; import java.sql.DatabaseMetaData; import java.sql.Statement; import java.sql.Connection; import javax.sql.RowSet; public final class SqlUtil { static void abortQuery(String query, String msg) throws JTaintException { @StringBuilder@ sb=new @StringBuilder@(query.length()+msg.length()+64); JTaintException e; sb.append(msg); sb.append("\nQuery : "); sb.append(query); sb.append("\nTaint Information: "); sb.append(query.@internal@taint()); sb.append('\n'); e = new JTaintException(sb.toString(), Configuration.sqlWhitelist); if (Configuration.sqlPolicyLogAttack) Log.attack("SQL Injection", e); throw e; } static void parseError(String query, String msg) { @StringBuilder@ sb=new @StringBuilder@(query.length()+msg.length()+64); sb.append("Parse error exception: "); sb.append(msg); sb.append("\nQuery: "); sb.append(query); sb.append('\n'); Log.error(new Throwable(sb.toString())); } public static void validateSqlConnection(String s, Object o) throws JTaintException { try { /* Don't check o for null, instanceof is never true for null */ if (!(o instanceof Connection) || s == null || !s.@internal@isTainted() || !Configuration.sqlPolicyEnabled) return; if (Configuration.sqlPolicyLogVuln) Log.vuln("SQL Injection", new JTaintException("Tainted Sql Query: " + s + "\n" + "Taint information " + s.@internal@taint(), Configuration.sqlWhitelist)); Connection c = (Connection) o; SqlValidator v = c.@internal@sqlValidator(); v.validateSqlQuery(s); } catch (JTaintException e) { if (!e.isWhitelisted()) throw e; } catch (Throwable e) { Log.error(e); } } public static void validateSqlStatement(String s, Object o) throws JTaintException { try { if (!(o instanceof Statement) || s == null || !s.@internal@isTainted()) return; Statement st = (Statement) o; validateSqlConnection(s, st.getConnection()); } catch (JTaintException e) { if (!e.isWhitelisted()) throw e; } catch (Throwable e) { Log.error(e); } } public static void validateSqlRowSet(String sql, Object o) { try { if (!(o instanceof RowSet) || sql == null || !sql.@internal@isTainted() || !Configuration.sqlPolicyEnabled) return; abortQuery(sql, "Tainted string used as RowSet SQL command"); } catch (JTaintException e) { if (!e.isWhitelisted()) throw e; } catch (Throwable e) { Log.error(e); } } public static SqlValidator getSqlValidator(Object o) { try { if (!(o instanceof Connection)) { Log.error(new Throwable("getSqlValidator(Bad object)")); return EmptySqlValidator.INSTANCE; } Connection c = (Connection) o; DatabaseMetaData dmd = c.getMetaData(); String dbName = dmd.getDatabaseProductName().toLowerCase(); int dbMajor = dmd.getDatabaseMajorVersion(); int dbMinor = dmd.getDatabaseMinorVersion(); if (dbName.indexOf("postgres") >= 0) return new PostgreSqlValidator(c, dbMajor, dbMinor); else if (dbName.indexOf("mysql") >= 0) return new MySqlValidator(c, dbMajor, dbMinor); else if (dbName.indexOf("hsql") >= 0) return new HypersonicSqlValidator(c, dbMajor, dbMinor); else if (dbName.indexOf("db2") >= 0) return new Db2SqlValidator(c, dbMajor, dbMinor); else if (dbName.indexOf("derby") >= 0) return new DerbySqlValidator(c, dbMajor, dbMinor); else if (dbName.indexOf("oracle") >= 0) return new OracleSqlValidator(c, dbMajor, dbMinor); else Log.error("Unknown database type " + dbName); } catch (Throwable th) { Log.error(th); } return EmptySqlValidator.INSTANCE; } }