Il existe un système qui permet aux utilisateurs de travailler avec des fichiers dans le navigateur. La pile technologique est standard : Java, Spring, React, Postgres. Les fichiers sont stockés dans le système de fichiers sur le backend, et les métadonnées des fichiers dans la base de données. L'équipe a implémenté une fonctionnalité : renommer un fichier. Cette méthode est essentielle pour renommer un fichier sur le backend. Une revue doit être effectuée pour identifier d'éventuels problèmes dans le code existant et proposer des solutions. @Transactional public void process(String oldName, String newName) { Long id = exec("select id from file where name='" + oldName + "'"); processFile(oldName, newName); // renommage du fichier sur le disque exec("update file set name='" + newName + "' where id = " + id); }
Réponse de l'IA
sobes.tech IA
В представленном методе есть несколько проблем:
-
SQL-инъекция: Использование конкатенации строк для формирования SQL-запросов (
"select id from file where name='" + oldName + "'") уязвимо для SQL-инъекций. -
Отсутствие обработки ошибок: Если файл с именем
oldNameне найден, методexecможет вернуть null или вызвать ошибку, что не обрабатывается. -
Потенциальная рассинхронизация: Переименование файла на диске и обновление записи в БД не атомарны, несмотря на аннотацию
@Transactional, так как файловая система не участвует в транзакции БД. -
Отсутствие проверки успешности переименования файла: Если
processFileне сработает, база данных уже будет обновлена, что приведет к рассинхронизации. -
Небезопасное обновление имени файла: Нет проверки, что
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);
}
Такой подход повышает безопасность и надежность операции.