У меня есть следующий код для загрузки таблицы в виде файла с использованием PG КОПИРОВАТЬ:
public void download(String table, Writer responseWriter) throws SQLException, IOException {
try (Connection conn = dataSource.getConnection()) {
CopyManager copyManager = new CopyManager(conn.unwrap(BaseConnection.class));
// SQL Injection can happen here!
String statement = "COPY " + table + " TO STDOUT WITH NULL ''";
copyManager.copyOut(statement, responseWriter);
}
}
Очевидно, что этот код подвержен внедрению SQL (параметр таблицы передается из контроллера Spring REST). Конечно, я могу сделать некоторую очистку вручную, но если в CopyManager есть способ "PreparedStatement", я бы предпочел его. Бонусные баллы за использование Spring JdbcTemplate.
В дополнение к общей инъекции SQL, когда злоумышленник пытается сделать что-то вроде добавления оператора DELETE
к вашей команде COPY
, есть еще одна проблема. Поскольку ваш код допускает запуск допустимого имени таблицы Любые, он по-прежнему рискует раскрыть данные, содержащиеся в любой таблице в вашей схеме.
Таким образом, безопасным решением здесь может быть создание белого списка таблиц, к которым вы хотите предоставить доступ пользователю. Любое имя входной таблицы, не соответствующее списку, будет отклонено. Предполагая, что ваш список таблиц находится в List
, мы могли бы внести в ваш код следующее изменение:
public void download(String table, Writer responseWriter) throws SQLException, IOException {
// get list of all allowed tables
List<String> fileList = getAllowedTables();
if (!fileList.contains(table)) {
throw new IllegalAccessException("Someone tried to access a forbidden table.");
}
try (Connection conn = dataSource.getConnection()) {
CopyManager copyManager = new CopyManager(conn.unwrap(BaseConnection.class));
// SQL Injection can happen here!
String statement = "COPY " + table + " TO STDOUT WITH NULL ''";
copyManager.copyOut(statement, responseWriter);
}
}