Sobes.tech
Middle+
61

Има система, която позволява на потребителите да работят с файлове в браузъра. Стекът от технологии е стандартен: Java, Spring, React, Postgres. Файловете се съхраняват във файловата система на бекенда, метаданните на файловете в базата данни. Екипът реализира функция: преименуване на файл. Този метод е по същество ключов за преименуване на файл на бекенда. Трябва да се проведе преглед, който да идентифицира потенциални проблеми в съществуващия код и да предложи решения. @Transactional public void process(String oldName, String newName) { Long id = exec("select id from file where name='" + oldName + "'"); processFile(oldName, newName); // преименуване на файла на диска exec("update file set name='" + newName + "' where id = " + id); }

Компаниите бяха попитани
СБЕРСБЕР

Отговор от 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);
}

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