Sobes.tech
Middle+
51

Istnieje system, który umożliwia użytkownikom pracę z plikami w przeglądarce. Stos technologiczny jest standardowy: Java, Spring, React, Postgres. Pliki są przechowywane w systemie plików na backendzie, metadane plików w bazie danych. Zespół zaimplementował funkcję: zmiana nazwy pliku. Ta metoda jest kluczowa dla zmiany nazwy pliku na backendzie. Należy przeprowadzić jej przegląd, aby zidentyfikować potencjalne problemy w istniejącym kodzie i zaproponować rozwiązania. @Transactional public void process(String oldName, String newName) { Long id = exec("select id from file where name='" + oldName + "'"); processFile(oldName, newName); // zmiana nazwy pliku na dysku exec("update file set name='" + newName + "' where id = " + id); }

Firmy, w których zadano pytania
СБЕРСБЕР

Odpowiedź od AI

sobes.tech AI

В представленном методе есть несколько проблем:

  1. SQL-инъекция: Использование конкатенации строк для формирования SQL-запросов ("select id from file where name='" + oldName + "'") уязвимо для SQL-инъекций.

  2. Отсутствие обработки ошибок: Если файл с именем oldName не найден, метод exec может вернуть null или вызвать ошибку, что не обрабатывается.

  3. Потенциальная рассинхронизация: Переименование файла на диске и обновление записи в БД не атомарны, несмотря на аннотацию @Transactional, так как файловая система не участвует в транзакции БД.

  4. Отсутствие проверки успешности переименования файла: Если processFile не сработает, база данных уже будет обновлена, что приведет к рассинхронизации.

  5. Небезопасное обновление имени файла: Нет проверки, что newName не конфликтует с уже существующими именами.

Рекомендации по исправлению:

  • Использовать параметризованные запросы или ORM (например, JPA) для безопасного доступа к базе.
  • Добавить проверку существования файла и обработку ошибок.
  • Сделать переименование файла и обновление БД атомарными с помощью механизма компенсации или отложенного обновления.
  • Проверять, что новое имя не занято.
  • Логировать операции и ошибки.

Пример исправленного кода с использованием JPA и обработки ошибок:

@Transactional
public void process(String oldName, String newName) {
    Optional<FileEntity> fileOpt = fileRepository.findByName(oldName);
    if (!fileOpt.isPresent()) {
        throw new FileNotFoundException("File with name " + oldName + " not found");
    }
    if (fileRepository.existsByName(newName)) {
        throw new IllegalArgumentException("File name " + newName + " already exists");
    }
    FileEntity file = fileOpt.get();
    try {
        processFile(oldName, newName); // переименование на диске
    } catch (IOException e) {
        throw new RuntimeException("Failed to rename file on disk", e);
    }
    file.setName(newName);
    fileRepository.save(file);
}

Такой подход повышает безопасность и надежность операции.