ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • CSV를 열었는데 수식이 실행된다면: 따옴표만으로 부족한 이유
    Data Analysis 2026. 10. 6. 00:28
    728x90
    반응형

    CSV의 인용 부호 처리와 수식·문자열 셀 해석의 차이
    무해한 산술 입력으로 두 해석을 비교한 개념도입니다. 특정 스프레드시트의 실행 화면은 아닙니다.

    CSV 내보내기에 따옴표 처리를 넣었는데, Excel에서 메모가 3으로 보입니다. 사용자가 적은 값은 =1+2였다고 해봅시다. CSV의 열 구분을 안전하게 만드는 처리와, 셀을 수식으로 읽지 않게 만드는 처리를 나눠야 합니다. 사람에게 보여 줄 파일이라면 셀의 데이터 형식을 명시할 수 있는 방식부터 검토하세요.

    따옴표 안의 값도 수식이 될 수 있습니다

    다음은 외부 연결이나 명령 실행이 없는, 설명용 산술 입력입니다.

    name,memo
    "sample","=1+2"
    

    CSV 파서는 따옴표를 이용해 어디까지가 한 필드인지 알아냅니다. 필드를 읽고 난 뒤의 값은 =1+2입니다. 이어서 스프레드시트 앱이 이 값을 수식으로 해석할 수 있습니다. CSV 문법상 제대로 된 한 셀이라는 사실이 그 셀의 해석 방식을 텍스트로 고정하지는 않습니다. OWASP CSV Injection

    이 문제는 사용자 이름, 상품 설명, 고객 메모처럼 원래는 계산과 관계없는 열에서도 생깁니다. 내보내기 코드는 입력을 그대로 옮겼는데, 파일을 여는 앱이 새로운 의미를 부여하는 지점이 생긴 것입니다.

    그렇다고 CSV 인용 처리가 불필요한 것은 아닙니다. 메모 안의 쉼표, 줄바꿈, 큰따옴표 때문에 열이 갈라지지 않도록 CSV 라이브러리로 직렬화해야 합니다. Python의 csv.writer가 처리하는 인용과 구분자 규칙은 이 파일 구조를 위한 기능입니다. Python csv 모듈

    내보내기 버튼의 용도부터 둘로 나눕니다

    가상의 고객 메모 서비스에서 두 요청이 들어왔다고 합시다. 운영자는 Excel에서 목록을 보고 싶고, 다른 시스템은 메모를 원문 그대로 가져가고 싶습니다. 두 요청에 같은 가공을 적용하면 한쪽의 요구를 망칠 수 있습니다.

    예를 들어 모든 값 앞에 작은따옴표나 탭을 추가하면, 기계가 읽는 메모에도 그 문자가 남을 수 있습니다. 원래 문자열과 내보낸 문자열이 달라지므로 검색이나 서명 비교에서 문제가 생길 수 있습니다. 반대로 원문 보존만 생각해 스프레드시트 열람 경로를 그대로 열어 두면 수식 해석을 처리하지 못합니다.

    따라서 화면에는 ‘스프레드시트에서 보기’와 ‘원본 데이터 내려받기’를 구분하는 편이 설명하기 쉽습니다. 전자는 텍스트 셀로 작성한 파일을 제공하고, 후자는 CSV 파서로 처리할 데이터를 보존합니다. CSV 파일명만 보고 어느 용도로 안전한지 사용자가 추측하게 두지 않는 것입니다.

    열람용 XLSX에는 문자열 쓰기를 명시합니다

    XLSX를 사용해도 어떤 API로 값을 넣는지가 중요합니다. XlsxWriter의 일반 write()는 입력에 따라 문자열과 수식 등을 구분합니다. 사용자 입력을 텍스트로 보여 주려면 write_string()처럼 문자열 쓰기를 명시할 수 있습니다. XlsxWriter write()와 write_string()

    아래는 앞선 메모를 열람용 파일로 만드는 예시입니다. 실제 Excel에서 열어 본 시험 결과는 아니며, 별도 작업 폴더에서 실행할 형태입니다.

    from xlsxwriter import Workbook
    
    user_memo = "=1+2"
    path = "memo-review.xlsx"
    with Workbook(path) as book:
        sheet = book.add_worksheet(
            "Memos"
        )
        sheet.write_string(
            0, 0, "memo"
        )
        sheet.write_string(
            1, 0, user_memo
        )
    

    이 코드는 사용자 값을 수식 쓰기 함수에 전달하지 않습니다. 숫자 계산이 필요한 다른 열은 검증된 숫자를 숫자 셀로 쓰고, 메모 열은 문자열로 쓰는 식으로 열의 용도에 맞춰 나눕니다. 사용자가 입력한 모든 것을 무조건 숫자로 변환하는 처리도 피할 수 있습니다.

    확인할 때는 셀 화면에 무엇이 보이는지만 보지 말고, 수식 입력줄과 셀 형식도 함께 봅니다. 예시의 목표는 계산 결과 3이 아니라 문자 =1+2가 남는 것입니다. 결과 파일을 저장하고 다시 열었을 때에도 같은지 확인해야 합니다. 이후 CSV로 다시 내보내는 흐름이 있다면 그 지점에서 데이터 형식 정보가 사라질 수 있으므로 별도 점검 대상입니다.

    CSV가 꼭 필요한 경로는 별도로 검증합니다

    레거시 프로그램이 CSV만 받거나 운영자가 CSV를 직접 열어야 한다면, 수신 앱과 여는 방식을 정해 놓고 방어 처리를 검증해야 합니다. OWASP는 수식으로 해석될 수 있는 시작 문자뿐 아니라 구분자와 줄바꿈을 통한 셀 경계 변화도 살피도록 안내합니다. 단순히 전체 입력의 첫 글자만 검사하는 방법으로는 셀마다 생기는 위험을 놓칠 수 있습니다. CSV Injection의 입력 경계

    여기서 보편적인 정규식 하나를 정답으로 내놓기는 어렵습니다. 앱의 버전·언어 설정·가져오기 경로와 저장 후 재열기 동작에 따라 처리가 달라질 수 있습니다. OWASP 역시 모든 스프레드시트와 후속 소비자에 공통으로 안전한 CSV 정제 방식은 없다고 설명합니다.

    테스트용 파일에는 실제 고객 정보를 넣을 필요가 없습니다. 예시처럼 무해한 산술 문자열과 쉼표·큰따옴표·줄바꿈이 든 메모를 넣어 보세요. 원본 입력, CSV 파서가 읽은 값, 스프레드시트에 표시된 값을 나란히 비교하면 어느 단계에서 바뀌었는지 좁힐 수 있습니다. 테스트는 사용하는 앱의 실제 ‘열기’ 또는 ‘가져오기’ 경로로 해야 합니다.

    예를 들어 memo가 두 줄이라고 해서 행이 두 개로 늘면 CSV 작성 단계가 잘못된 것입니다. 하나의 셀 안에 남지만 산술 결과로 바뀌면 셀 해석 단계가 문제입니다. 원문에 없던 탭이 다른 시스템까지 전달되면 열람용 가공이 데이터 전달 경로에 섞인 것입니다. 셋은 서로 다른 실패라 고치는 위치도 다릅니다.

    서버 검증과 파일 작성은 각각 필요합니다

    메모를 받는 서버에서 길이와 허용 형식을 검증하고, 내보낼 때도 사용할 파일 형식에 맞게 작성합니다. 이미 저장된 오래된 값이나 다른 경로에서 들어온 값까지 있으므로, 입력 화면 하나에 검사 코드를 넣었다고 출력 처리를 생략할 수는 없습니다.

    당장 확인할 곳은 CSV 내보내기의 따옴표 개수가 아니라 사용자 값이 마지막에 어떤 셀 타입으로 전달되는지입니다. 운영자가 읽을 파일은 문자열 셀로 작성하고, 시스템이 읽을 원본 데이터는 별도 경로로 보존하세요. 기존 CSV를 유지한다면 실제 수신 앱에서 저장·재열기까지 포함해 메모가 문자로 남는지 확인해야 합니다.

    자료 확인: 2026년 9월 28일. 이 글은 방어 설계 설명이며 특정 스프레드시트 버전에서의 실행 결과를 보고한 글은 아닙니다.

    728x90
    반응형
Designed by Tistory.