File을 input에 넣어주고 싶은데... [티]

eeensu·2025년 8월 15일

Javascript

목록 보기
39/41

개요

이미지 파일을 가진 데이터의 수정 페이지를 만들고 있었다. 이때 데이터를 최초 생성할 땐 input에 File 데이터를 넣어서 FormData로 보내거나 uploadthing과 같은 클라우드 이미지 저장소를 거쳐 이미지 url만 전송하는 등의 작업을 할 수 있을것이다.

이때 이 생성된 데이터를 수정할 떄, 마찬가지로 기존 데이터의 이미지도 있을테다. 그리고 그냥 간단하게, 되진 않겠지만 input 태그에 서버에서 받아온 File을 넣을 순 없나? 라고 생각해봤다. 시도했지만 당연히 되지 않았다.. 흑흐긓... 다른 방법을 찾아봐야지 하기전에 왜 안될까를 정리해보고자 한다.




보안상의 제한

브라우저는 input type file 요소에 대해서 엄격한 제안을 둔다.

  1. 사용자의 의도와 통제권 보장
  • 브라우저는 파일업로드는 사용자만 할 수 있는 행위로 간주
  • 이는 웹사이트가 사용자의 로컬 파일에 접근하거나, 업로드하는 것을 사용자가 명확히 인지하고 있어야 한다는 원칙
  • 사용자가 input[type="file"]을 클릭해서 파일을 선택하지 않았다면, 어떠한 방식으로든 자동으로 파일이 채워지면 안 된다.

사실 생각해 보면 맞다. 사용자가 의도치 않은 파일이 올려지면 매우 위험할수도 있다...


  1. input.filesFileList 타입이고 읽기 전용
const file = new File(['hello'], 'hello.txt', { type: 'text/plain' });
fileInput.files = [file]; // 이건 불가능하다

만약 이 제한이 없으면 아래와 같은 무단 파일 업로드 악성 스크립트같은 것들이 들어가 다음과 같은 상황이 벌어질 수 있는 것이다....

const file = await fetch('private한 주소..').then(res => res.blob());
input.files = [file];
form.submit();


  1. FileList는 생성 자체가 불가능한 설계!
    심지어 new FileList() 같은 생성자도 제공되지 않는다.
    즉, input.files에 넣을 수 있는 객체를 브라우저 외부에서는 만들 수 없도록 설계되어 있다.



대안은?

파일을 다시 업로드하거나 보여주기 위한 목적이라면 다음의 방법을 사용할 수 있다. 물론 여전히 input 태그에 files를 직접 넣지는 못한다.

  1. Blob/File을 <img> 또는 <a download> 등으로 사용하기
const response = await fetch('이미지 url 정보가 대충 들어갈듯');
const blob = await response.blob();
const url = URL.createObjectURL(blob);

// <img src={url} /> 이렇게 사용

  1. 해당 이미지 파일의 id 값을 재사용하는 등의 처리

이러할 경우 서버에서 해당 파일을 재사용하거나, 사용자가 새 파일을 업로드하지 않으면 기존 파일 경로 혹은 id 값만 유지해서 전송하는 방식으로 처리하는것이 깔끔하다.



html 스펙 관점에서 볼때, input[type=file]은 오로지 유저 상호작용시에만 작동하며, html 차원에서 유일하게 의도적으로 조작이 불가능하게 설계된 유일한 input이다.

profile
안녕하세요! 프론트엔드 개발자입니다! (2024/03 ~)

0개의 댓글