이야기를 디버깅하는 개발자.

개발과 창작 사이에서, 사람들이 자기만의 이야기를 만들 수 있는 도구와 기록을 만듭니다.

roslyn.dev 자세히보기

만드는 기록/작게 만든 도구들

CSV 내보내기에서 사용자 입력을 수식으로 읽지 않게 하는 법

Roslyn 2026. 11. 14. 08:00
반응형

문의 목록을 CSV로 내려받는 기능은 단순해 보입니다. 이름과 제목, 작성일을 쉼표로 연결하고 파일로 보내면 끝날 것 같습니다. 하지만 같은 파일을 다른 프로그램이 열 때에는 문자열을 나열했다는 사실만으로 표시 방식까지 결정되지 않습니다. 특히 사용자가 적은 내용을 스프레드시트에서 열도록 제공한다면 값의 해석을 별도로 다뤄야 합니다.

개인 서비스의 작은 내보내기 도구를 설계할 때 중요한 질문은 두 가지입니다. 값 하나가 셀 하나에 남는지, 그리고 그 값이 의도한 자료형으로 읽히는지입니다. 이 글은 2026년 11월 1일 확인한 보안 문서를 바탕으로 점검 순서를 제안합니다. 특정 Excel이나 LibreOffice 버전에서 실행해 방어를 검증한 구현 후기는 아닙니다.

따옴표로 감싸는 일과 수식을 막는 일은 다릅니다

OWASP의 CSV Injection 문서는 신뢰하지 않는 입력이 스프레드시트에서 수식으로 해석되는 문제를 설명합니다. 등호로 시작하는 값뿐 아니라 더하기, 빼기, 골뱅이, 탭과 줄바꿈, 일부 환경의 전각 문자도 검토 대상으로 제시합니다. 또한 구분자와 따옴표 때문에 새로운 셀이 생기는 경우를 함께 고려하라고 안내합니다.

여기서 CSV 문법과 수식 해석은 다른 층입니다. CSV를 올바르게 작성해 쉼표가 들어 있는 제목을 한 셀에 담더라도, 그 셀의 내용이 수식으로 해석되지 않는다는 보장은 없습니다. 반대로 첫 글자만 검사하면서 구분자 처리를 잘못하면 하나의 입력이 여러 셀로 나뉘어 예상과 다른 시작 값이 생길 수 있습니다.

가상의 문의 제목이 =1+1이라고 해 보겠습니다. 작성자는 이 문자열 자체를 문의한 것일 수 있습니다. 관리자가 확인하려는 것은 입력된 네 문자입니다. 프로그램이 계산한 숫자 2만 보여 준다면 악의적인 입력이 아니어도 원래 자료를 제대로 확인하지 못한 것입니다. 이 예시는 외부 연결이나 명령 실행을 포함하지 않는 단순 계산 예시입니다.

첫 점검은 화면의 결과에서 시작합니다. 원래 입력, 파일에 기록한 필드, 프로그램이 표시한 셀을 나란히 비교합니다. 값이 다르면 어느 단계에서 바뀌었는지 구별해야 합니다. 문자열을 잘라 냈는지, 셀 경계가 달라졌는지, 열기 과정에서 계산됐는지를 섞어 처리하면 한 문제를 고치면서 다른 자료를 손상시킬 수 있습니다.

누가 여는 파일인지와 열의 의미를 먼저 정합니다

같은 CSV라도 관리자가 눈으로 검토하는 파일과 다른 시스템으로 옮기는 파일은 요구가 다릅니다. 사람에게 보여 주기 위해 접두 문자를 추가한 값이 다음 시스템에서는 실제 데이터가 될 수 있습니다. 표시를 안전하게 하려는 조치가 검색, 중복 비교, 외부 식별자 연결을 바꿀 수 있다는 뜻입니다. 원본 데이터와 표시용 변환 결과를 구분해 보관해야 하는 이유입니다.

내보내기 명세에는 열 이름만 적지 말고 의미도 적습니다. 이름과 문의 제목은 텍스트인지, 금액은 검증한 숫자인지, 상품 코드는 앞자리 0이 의미 있는 식별자인지 정합니다. 빼기 기호가 위험 시작 문자 목록에 있다는 이유만으로 정상적인 음수 금액을 모두 잘라 내는 식의 처리는 적절하지 않습니다. 같은 문자라도 열의 계약이 다릅니다.

  • 입력 출처: 이용자 입력, 외부 시스템 값, 서버에서 계산한 값을 구분합니다.
  • 열의 의미: 텍스트, 숫자, 날짜, 식별자 중 기대하는 해석을 정합니다.
  • 이용 경로: 파일을 직접 여는지, 가져오기 기능을 쓰는지, 다른 코드가 읽는지 적습니다.
  • 원본 보존: 표시용 변환으로 달라진 문자가 원래 값과 혼동되지 않도록 관리합니다.

예를 들어 문의 검토용 다운로드와 데이터 이전용 다운로드를 별도로 제공할 수 있습니다. 파일 이름과 화면 설명에도 용도를 표시합니다. 어느 쪽이든 “안전한 CSV”라는 이름 하나로 사용자가 모든 프로그램에서 동일한 결과를 얻는다고 기대하게 해서는 안 됩니다. 지원하는 열기 방식과 확인하지 않은 사용 경로를 구분하는 편이 낫습니다.

다른 시스템으로 전달하는 값이라면 표시용 문자를 붙이는 정책보다 입력 계약과 수신 측의 처리 방식이 먼저입니다. 원본을 보존해야 하는 열을 임의로 고치지 않고, 허용하지 않는 값은 오류로 알려 사용자가 수정하게 할 수도 있습니다. 다만 자유로운 문의 제목에 지나치게 좁은 규칙을 적용하면 정상 입력을 잃으므로, 자료의 목적과 사용자 작업을 함께 검토해야 합니다.

대상 프로그램과 재저장 경로까지 방어 범위를 잡습니다

OWASP 문서는 작은따옴표를 앞에 붙이는 방식 등이 Excel에서 저장 후 다시 열 때 신뢰되지 않을 수 있다고 경고합니다. 또 따옴표 안의 탭 접두 방식을 Excel용 대안으로 설명하지만 다른 프로그램의 동작 차이와 실제 데이터에 탭이 남는 영향을 함께 적습니다. 모든 프로그램과 후속 처리에 통하는 단일 정제 규칙은 없다는 점이 핵심입니다.

따라서 문서의 예시를 함수 하나로 복사하기 전에 지원 범위를 결정해야 합니다. 대상 프로그램, 버전, 언어 설정, 구분자, 직접 열기와 가져오기 방식, 다시 저장하는지 여부를 확인 항목으로 둡니다. 이용자가 파일을 받은 뒤 하는 행동까지 전부 통제할 수 없다면 검증한 경로와 검증하지 못한 경로를 분명히 나눕니다.

실제 구현에서는 CSV 문법을 담당하는 검증된 라이브러리와 열별 값 정책의 역할을 분리하는 편이 점검하기 좋습니다. 라이브러리가 구분자와 따옴표를 처리한다고 수식 방어까지 해 준다고 가정하지 않습니다. 반대로 값 정책을 적용했더라도 파일 생성 단계에서 셀 경계가 유지되는지는 별도로 살핍니다. 의존성의 기능 범위는 선택한 라이브러리 문서에서 확인해야 합니다.

표시용 변환은 가능한 한 내보내기 경계에서 적용하고, 데이터베이스의 원본 값을 같은 방식으로 덮어쓰지 않는 설계를 검토할 수 있습니다. 그래야 정책을 바꿨을 때 원래 입력을 다시 확인할 수 있습니다. 이 역시 모든 서비스의 정답은 아닙니다. 개인정보 보관 정책이나 원본 삭제 요건이 있다면 그 조건이 함께 반영되어야 합니다.

문제가 생겼을 때 관리자가 보안 경고를 무조건 무시하도록 안내해서는 안 됩니다. 경고를 없애는 것과 기대한 값이 안전하게 보이는 것은 다릅니다. 다운로드 화면에는 확인된 사용 방법을 적고, 예상과 다른 동작이 생기면 파일을 계속 편집하기 전에 담당자가 생성 경로를 조사할 수 있게 합니다.

작은 검사표에 원본과 표시 결과를 함께 남깁니다

검사 자료는 실제 고객의 문의를 가져오기보다 별도로 만든 무해한 문자열로 준비할 수 있습니다. 일반 한글 제목, 쉼표와 큰따옴표가 있는 제목, 여러 줄 텍스트, 앞자리 0이 있는 코드, 단순 계산 모양의 문자열을 포함합니다. 금액 열에는 정상적인 음수와 숫자가 아닌 값을 구분해 넣습니다. 각 행에는 기대하는 셀 수와 표시값을 먼저 적습니다.

검사는 세 구간으로 나눌 수 있습니다. 생성 파일이 명세의 열 수를 유지하는지 확인하고, 대상 프로그램에서 기대한 텍스트나 숫자로 보이는지 살핀 뒤, 지원 범위에 재저장이 있다면 저장 후 다시 열어 결과를 비교합니다. 파일 생성만 통과한 상태를 스프레드시트 표시까지 확인했다고 기록하지 않습니다.

예를 들어 제목 열의 단순 계산 문자열은 계산 결과가 아니라 원래 입력처럼 보여야 한다고 정할 수 있습니다. 코드 열의 앞자리 0은 남아야 하고, 쉼표가 있는 제목은 옆 열로 밀려나지 않아야 합니다. 이처럼 기대 결과를 구체적으로 적으면 접두 문자를 넣었다는 구현 사실보다 실제 사용 목적을 기준으로 검토할 수 있습니다.

프로그램 버전이나 파일 생성 라이브러리, 열의 자료형, 열기 방식이 바뀌면 해당 검사표를 다시 사용합니다. 예전에 한 번 열렸다는 기억만으로 다음 변경을 통과시키지 않습니다. 문제가 있는 경로를 아직 해결하지 못했다면 그 경로를 지원한다고 안내하지 말고 제한을 남기는 편이 낫습니다.

오늘은 내 서비스의 CSV 한 종류를 골라 “누가 어떤 프로그램으로 열고, 그 뒤 어디에 다시 쓰는가”를 한 줄로 적어 보시면 좋겠습니다. 그 문장이 정해져야 값의 보존과 표시 안전성 사이에서 필요한 정책을 선택할 수 있습니다. 작은 다운로드 기능도 파일을 만드는 순간보다 사용자가 값을 읽는 순간을 기준으로 설계하면 확인할 경계가 선명해집니다.

반응형