Предотвращение внедрения SQL с помощью PostgreSQL COPY JDBC

#java #postgresql #jdbc

#java #postgresql #jdbc

Вопрос:

У меня есть следующий код для загрузки таблицы в виде файла, используя PG COPY:

     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). Конечно, я могу выполнить некоторую ручную очистку, но если есть способ «PreparedStatement» сделать это в CopyManager, я бы предпочел это. Бонусные баллы за использование JdbcTemplate от Spring.

Ответ №1:

В дополнение к общей 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);
    }
}