Как я санирую SQL, не используя подготовленные операторы

Также очень новое: https://github.com/denniskuczynski/beanstalkd_view (приложение Ruby / Sinatra)

15
задан ThiefMaster 25 March 2012 в 15:31
поделиться

3 ответа

Right, prepared statement query parameters can be used only where you would use a single literal value. You can't use a parameter for a table name, a column name, a list of values, or any other SQL syntax.

So you have to interpolate your application variable into the SQL string and quote the string appropriately. Do use quoting to delimit your table name identifier, and escape the quote string by doubling it:

java.sql.DatabaseMetaData md = conn.getMetaData();
String q = md.getIdentifierQuoteString();
String sql = "SELECT MAX(AGE) FROM %s%s%s";
sql = String.format(sql, q, tablename.replaceAll(q, q+q), q);

For example, if your table name is literally table"name, and your RDBMS identifier quote character is ", then sql should contain a string like:

SELECT MAX(AGE) FROM "table""name"

I also agree with @ChssPly76's comment -- it's best if your user input is actually not the literal table name, but a signifier that your code maps into a table name, which you then interpolate into the SQL query. This gives you more assurance that no SQL injection can occur.

HashMap h = new HashMap<String,String>();
/* user-friendly table name maps to actual, ugly table name */
h.put("accounts", "tbl_accounts123");

userTablename = ... /* user input */
if (h.containsKey(userTablename)) {
  tablename = h.get(userTablename);
} else {
  throw ... /* Exception that user input is invalid */
}
String sql = "SELECT MAX(AGE) FROM %s";
/* we know the table names are safe because we wrote them */
sql = String.format(sql, tablename); 
17
ответ дан 1 December 2019 в 03:52
поделиться

Not possible. Best what you can do is to use String#format().

String sql = "SELECT MAX(AGE) FROM %s";
sql = String.format(sql, tablename);

Note that this doesn't avoid SQL injection risks. If the tablename is a user/client-controlled value, you'd need to sanitize it using String#replaceAll().

tablename = tablename.replaceAll("[^\\w]", "");

Hope this helps.

[Edit] Я должен добавить: НЕ используйте это для значений столбцов, для которых вы можете использовать PreparedStatement . Просто продолжайте использовать его обычным способом для любых значений столбца.

[Edit2] Лучше всего не позволять пользователю / клиенту вводить имя таблицы так, как он хочет, но лучше представить раскрывающийся список, содержащий все допустимые имена таблиц (которые вы можете получить с помощью DatabaseMetaData # getCatalogs () ) в пользовательском интерфейсе, чтобы пользователь / клиент мог выбрать его. Не забудьте проверить на стороне сервера, действителен ли выбор, потому что можно подделать параметры запроса.

2
ответ дан 1 December 2019 в 03:52
поделиться

In this case you could validate the table name against the list of available tables, by getting the table listing from the DatabaseMetaData. In reality it would probably just be easier to use a regex to strip spaces, perhaps also some sql reserved words, ";", etc from the string prior to using something liek String.format to build your complete sql statement.

The reason you can't use preparedStatement is because it is probably encasing the table name in ''s and escaping it like a string.

0
ответ дан 1 December 2019 в 03:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: