SaaS에 맡긴 파일, 구글에 노출된다 — Fiverr 사례와 보안 체크리스트

목차

SaaS 파일 저장의 구조적 문제

SaaS 플랫폼에서 파일을 주고받을 때, 그 파일이 어디에 어떻게 저장되는지 신경 쓰는 사람은 생각보다 적다. 대부분은 "플랫폼이 알아서 관리하겠지"라고 생각한다. 문제는 그 "알아서"의 실체가 S3 버킷에 퍼블릭 URL을 붙여놓은 것일 수 있다는 점이다.

최근 Hacker News에서 Fiverr의 파일 저장 방식이 화제가 됐다. 고객이 프리랜서에게 전달한 파일 — 소스코드, 디자인 원본, 사업 계획서 같은 것들이 구글 검색에 그대로 노출되고 있었다. site:fiverr-res.cloudinary.com 같은 검색어로 누구나 접근할 수 있었다는 거다.

외주 맡기면서 .env 파일이나 DB 스키마가 담긴 문서를 아무 생각 없이 올리는 경우가 있을 텐데, 이번 사건은 그게 얼마나 위험한 행위인지 보여준 케이스다.

관련 추천 상품 보기 — 개발자를 위한 추천 장비와 도구를 확인해보세요. 쿠팡에서 보기 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

Fiverr 사건 — 무엇이 노출됐나

핵심은 단순하다. Fiverr에서 주문 과정 중 전달되는 파일들이 인증 없이 접근 가능한 CDN URL로 저장됐고, 해당 URL이 robots.txt로 차단되지 않아 구글 크롤러가 수집해간 것이다.

노출된 파일 유형

HN 스레드에서 보고된 내용을 보면, 노출 범위가 꽤 넓었다:

  • 로고, 배너 같은 디자인 시안 (이건 그나마 피해가 적다)
  • WordPress 사이트의 전체 소스코드를 ZIP으로 압축해서 전달한 케이스
  • AWS 크레덴셜이 포함된 설정 파일
  • 고객사의 내부 문서, 사업 계획서

디자인 파일 정도야 유출되어도 큰 문제가 아닐 수 있지만, AWS 크레덴셜이 포함된 파일이 공개 URL에 올라가 있었다면 이건 심각한 보안 사고다. 실제로 공격자가 이런 URL 패턴을 자동으로 스캔하는 도구를 돌리고 있다는 건 이미 알려진 사실이다.

기술적 원인

파일 저장 아키텍처를 추정해보면 이렇다:

사용자 업로드 → Fiverr 서버 → Cloudinary/S3 (퍼블릭 버킷)
                                    ↓
                              인증 없는 고정 URL 생성
                                    ↓
                              Google 크롤러 인덱싱

문제가 되는 지점은 두 가지다. 첫째, 파일 URL에 만료 시간이 없다. S3 Presigned URL을 쓰면 일정 시간 후 접근이 차단되는데, Fiverr는 영구적인 퍼블릭 URL을 사용한 것으로 보인다. 둘째, CDN 도메인에 대한 robots.txt 설정이 없거나 부실했다. 크롤러 입장에서는 "인덱싱해도 된다"는 신호를 받은 셈이다.

Google Dorking으로 직접 확인하는 법

내가 이 사건을 보고 제일 먼저 한 건, 우리 팀에서 쓰는 SaaS들의 파일이 혹시 노출되어 있는지 확인하는 거였다. Google Dorking은 특별한 도구 없이 구글 검색만으로 할 수 있어서 진입 장벽이 낮다.

기본 검색 연산자 몇 개만 알면 된다:

# 특정 SaaS 도메인의 파일 인덱싱 확인
site:storage.example-saas.com filetype:pdf

# 특정 파일 확장자로 범위 좁히기
site:cdn.example-saas.com filetype:zip OR filetype:sql OR filetype:env

# 회사명이 포함된 노출 파일 검색
"mycompany" filetype:xlsx site:*.cloudinary.com

실제로 돌려보면 생각보다 많은 결과가 나올 수 있다. 한번은 우리 팀에서 쓰던 프로젝트 관리 도구의 첨부파일이 구글에 인덱싱되어 있는 걸 발견한 적이 있다. 파일 자체는 내부 회의록이라 민감도가 높진 않았지만, URL 패턴을 알면 다른 파일도 유추할 수 있다는 게 찜찜했다.

자동화하려면 Python 스크립트로 만들 수도 있다:

import requests
from urllib.parse import quote

# Google Custom Search API 사용
# (주의: Google 검색을 직접 스크래핑하면 차단당한다)
API_KEY = "your-api-key"
CSE_ID = "your-cse-id"

def check_exposure(domain: str, filetypes: list[str]) -> list[dict]:
    """SaaS 도메인에서 노출된 파일 검색"""
    results = []
    for ft in filetypes:
        query = f"site:{domain} filetype:{ft}"
        url = (
            f"https://www.googleapis.com/customsearch/v1"
            f"?key={API_KEY}&cx={CSE_ID}&q={quote(query)}"
        )
        resp = requests.get(url, timeout=10)
        data = resp.json()
        
        # 검색 결과가 있으면 노출된 것
        if data.get("searchInformation", {}).get("totalResults", "0") != "0":
            results.append({
                "domain": domain,
                "filetype": ft,
                "count": data["searchInformation"]["totalResults"],
                "sample": data.get("items", [{}])[0].get("link", "N/A")
            })
    return results

# 점검할 SaaS 도메인 목록
domains = [
    "storage.slack-files.com",
    "files.notion.so",
    "cdn.fiverr-res.cloudinary.com",
]

sensitive_types = ["env", "sql", "zip", "csv", "xlsx", "json", "pem"]

for domain in domains:
    exposed = check_exposure(domain, sensitive_types)
    if exposed:
        print(f"[경고] {domain}에서 파일 노출 감지:")
        for item in exposed:
            print(f"  - .{item['filetype']}: {item['count']}건")

이건 주기적으로 돌려야 의미가 있다. cron으로 주 1회 정도 걸어두면 새로운 노출이 생겼을 때 빠르게 잡을 수 있다.

SaaS 파일 보안 — 뭘 봐야 하는가

SaaS를 선택할 때 기능, 가격, UX만 보는 경우가 많은데, 파일 저장 방식도 확인해야 한다. 아래는 점검 기준이다.

점검 항목 안전 위험
파일 URL 인증 Presigned URL (만료 시간 있음) 고정 퍼블릭 URL
robots.txt 파일 저장 경로 Disallow 설정 없음 or Allow
접근 권한 로그인한 사용자만 접근 URL만 알면 누구나 접근
파일 만료 일정 기간 후 자동 삭제 영구 보관
전송 암호화 TLS + 저장 시 암호화 (AES-256) TLS만 적용
감사 로그 파일 접근 로그 제공 로그 없음

대부분의 SaaS가 TLS는 적용하고 있다. 전송 중 암호화는 거의 기본이 된 상태다. 문제는 저장 후의 접근 제어인데, 여기서 차이가 크게 갈린다.

Presigned URL vs 퍼블릭 URL

AWS S3를 예로 들면, 같은 파일이라도 접근 방식이 완전히 다르다:

import boto3
from datetime import datetime

s3_client = boto3.client("s3")

# 나쁜 예: 퍼블릭 URL (영구적, 누구나 접근 가능)
bad_url = "https://my-bucket.s3.amazonaws.com/uploads/client-data.zip"

# 좋은 예: Presigned URL (1시간 후 만료)
good_url = s3_client.generate_presigned_url(
    "get_object",
    Params={
        "Bucket": "my-bucket",
        "Key": "uploads/client-data.zip",
    },
    ExpiresIn=3600,  # 3600초 = 1시간
)
# 결과: https://my-bucket.s3.amazonaws.com/uploads/client-data.zip
#        ?X-Amz-Expires=3600&X-Amz-Signature=abc123...

Presigned URL은 서명 파라미터가 붙어서 만료 시간이 지나면 AccessDenied를 반환한다. 구글 크롤러가 수집해가더라도 만료된 URL이면 인덱싱이 풀리게 된다.

robots.txt가 왜 중요한가

CDN이나 파일 저장소 도메인에 robots.txt를 설정하는 건 가장 기본적인 방어다. 이건 간단하다.

# cdn.example.com/robots.txt
User-agent: *
Disallow: /uploads/
Disallow: /files/
Disallow: /attachments/

물론 robots.txt는 강제가 아니라 권고 사항이라, 악의적인 크롤러는 무시할 수 있다. 그래서 이것만으로는 부족하고 인증 기반 접근 제어와 함께 써야 한다.

업로드 전 클라이언트 측 암호화

SaaS 플랫폼의 보안을 100% 신뢰할 수 없다면, 업로드 전에 클라이언트 측에서 암호화하는 방법이 있다. 실제로 우리 팀에서는 외부 플랫폼에 민감한 파일을 보낼 때 이 방식을 쓰기 시작했다.

from cryptography.fernet import Fernet
import base64
import hashlib

def encrypt_file(file_path: str, password: str) -> str:
    """파일을 암호화해서 .enc 파일로 저장"""
    # 패스워드에서 키 생성
    key = base64.urlsafe_b64encode(
        hashlib.sha256(password.encode()).digest()
    )
    fernet = Fernet(key)
    
    with open(file_path, "rb") as f:
        original = f.read()
    
    encrypted = fernet.encrypt(original)
    
    output_path = file_path + ".enc"
    with open(output_path, "wb") as f:
        f.write(encrypted)
    
    print(f"암호화 완료: {output_path} ({len(encrypted)} bytes)")
    return output_path

# 사용 예시
# SaaS에 올리기 전에 암호화
encrypt_file("database_schema.sql", "shared-secret-with-freelancer")

이렇게 하면 설령 URL이 노출되더라도 파일 내용은 보호된다. 수신자에게 패스워드를 별도 채널(Signal, 전화 등)로 전달하면 된다.

간단한 방법으로는 그냥 zip에 패스워드를 거는 것도 있다:

# 패스워드 보호된 ZIP 생성
zip -e sensitive_files.zip database_schema.sql config.json
# Enter password: ********

도구가 뭐든 핵심은 "플랫폼에 올라간 파일이 평문이면 안 된다"는 것이다.

실무 체크리스트 — SaaS에 파일 올리기 전

SaaS 보안 정책을 전부 분석하는 건 현실적으로 어렵다. 대신 실무에서 바로 적용할 수 있는 기준을 몇 가지로 줄였다.

파일 민감도 분류

모든 파일을 같은 수준으로 보호할 필요는 없다. 올리기 전에 3초만 생각하면 된다:

  • Level 3 (절대 올리면 안 됨): .env, .pem, 크레덴셜, API 키, SSH 키. 이런 건 SaaS에 올리는 것 자체가 잘못이다.
  • Level 2 (암호화 후 올릴 것): 소스코드, DB 스키마, 내부 문서, 고객 데이터가 포함된 파일.
  • Level 1 (그냥 올려도 됨): 공개 가능한 디자인 시안, 마케팅 자료, 공개된 문서.

Level 3에 해당하는 파일을 Fiverr 같은 플랫폼에 올리는 사람이 있다는 게 놀랍지만, 실제로 HN 스레드에서 AWS 크레덴셜이 노출된 사례가 보고됐다.

Git 레포에서 민감 파일 걸러내기

외주를 줄 때 레포를 통째로 ZIP으로 묶어서 보내는 경우가 있는데, 이때 .env나 시크릿 파일이 같이 딸려가는 경우가 많다. 보내기 전에 한 번 걸러주는 스크립트를 만들어 두면 편하다:

#!/bin/bash
# export-safe.sh — 민감 파일 제외하고 ZIP 생성

EXCLUDE_PATTERNS=(
    "*.env"
    "*.env.*"
    "*.pem"
    "*.key"
    "*credentials*"
    "*secret*"
    ".git"
    "node_modules"
)

EXCLUDE_ARGS=""
for pattern in "${EXCLUDE_PATTERNS[@]}"; do
    EXCLUDE_ARGS="$EXCLUDE_ARGS --exclude=$pattern"
done

# tar로 묶어서 민감 파일 제외
tar czf project-export.tar.gz $EXCLUDE_ARGS ./src ./docs ./README.md

echo "안전한 파일만 묶었다: project-export.tar.gz"
echo "제외된 패턴:"
printf '  - %s\n' "${EXCLUDE_PATTERNS[@]}"

이 정도만 해도 "실수로 .env 보냄" 사고는 막을 수 있다.

SaaS 선택 시 파일 보안 확인 방법

새로운 SaaS를 도입할 때 보안 문서를 확인하는 법을 몰라서 그냥 넘기는 경우가 많다. 확인 포인트는 의외로 간단하다.

첫째, 해당 SaaS의 보안 페이지를 찾는다. 대부분 trust.example.com이나 example.com/security에 있다. SOC 2 인증 여부가 나와 있으면 최소한의 접근 제어는 갖추고 있다고 볼 수 있다.

둘째, 파일 URL 패턴을 직접 확인한다. 테스트 파일 하나를 올리고, 공유 링크를 받아본다. 그 URL을 시크릿 브라우저(로그인 안 된 상태)에서 열어본다. 열리면 인증 없이 접근 가능하다는 뜻이다.

셋째, robots.txt를 확인한다. 파일이 저장된 CDN 도메인의 /robots.txt를 열어보면 크롤링 정책을 알 수 있다:

# CDN 도메인의 robots.txt 확인
curl -s https://cdn.example-saas.com/robots.txt

이 세 가지만 확인해도 해당 SaaS의 파일 보안 수준을 대략 파악할 수 있다. 시간은 5분이면 충분하다.

필요한 장비가 있다면 쿠팡에서 찾아보기 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

언제 신경 쓰고 언제 넘어갈 것인가

모든 SaaS 사용에 이 수준의 점검을 적용하는 건 과하다. 기준을 잡아야 한다.

반드시 점검해야 하는 경우: 소스코드, 인프라 설정, 고객 데이터, 계약서 등 유출 시 실질적 피해가 발생하는 파일을 외부 SaaS에 업로드하는 상황. Fiverr, Upwork 같은 프리랜서 플랫폼에 개발 관련 파일을 올릴 때가 대표적이다.

적당히 넘어가도 되는 경우: 이미 공개된 정보이거나, 유출돼도 피해가 없는 파일. 마케팅 배너 시안을 Fiverr에 올리는 건 크게 문제될 게 없다.

실질적인 액션은 세 가지다. 하나, 지금 쓰고 있는 SaaS에 올린 파일 중 Level 2 이상이 있는지 확인한다. 둘, Google Dorking으로 해당 SaaS 도메인의 파일 노출 여부를 검색해본다. 셋, 앞으로 민감 파일을 올릴 때는 클라이언트 측 암호화를 적용한다. 이 세 가지면 Fiverr 같은 사고에서 최소한 내 파일은 지킬 수 있다.

관련 글

Chiko IT
Chiko IT

Platform Engineer. Python, AI, Infra에 관심이 많습니다.