입력은 언제나 거짓말을 한다: 입력 검증과 인젝션 입문

아프로·2026년 10월 29일

입력은 언제나 거짓말을 한다 표지

이 글은 인프런 강의 「백엔드 개발자를 위한 서버 보안 실무」 섹션 2를 입문자용으로 풀어 쓴 글이에요.

수량: -3개

쇼핑몰 주문 API를 만들었다고 해 볼게요. 요청 본문에서 상품 번호와 수량을 꺼내 금액을 계산하고 저장합니다. 화면에서는 수량을 1 이상만 고를 수 있게 막아 두었어요.

그런데 누군가 화면을 거치지 않고 API를 직접 부르면서, 수량에 -3을 넣습니다. 금액이 음수가 되고, 그 주문이 그대로 저장돼요. 문자열이나 배열이 들어오면 어떻게 될지는 아무도 모릅니다.

이 코드는 "입력은 늘 착하다"고 가정하고 있었던 거예요. 하지만 서버에 도착한 입력은 누구든 마음대로 바꿔 보낼 수 있습니다. 화면의 제약은 사용자 편의일 뿐, 보안이 아니에요.

차단 목록이 아니라 허용 목록

입력을 거르는 방법은 크게 두 가지예요.

차단 목록과 허용 목록 비교

차단 목록은 "작은따옴표나 스크립트 태그 같은 위험한 패턴"을 찾아서 막습니다. 직관적이지만, 인코딩을 바꾸는 새 우회 방법이 나오면 뚫려요. 공항 보안 검색에 비유하면 "금지 물품 목록에 없는 건 다 통과"인 셈입니다.

허용 목록은 반대예요. 받을 값의 타입, 길이, 형식, 범위를 먼저 정하고, 그 모양이 아니면 전부 거절합니다. "탑승권에 적힌 사람, 정해진 크기의 가방만 통과"죠. 기본은 언제나 허용 목록이고, 그 규칙은 코드 곳곳에 흩어 두지 말고 스키마 한 곳에 선언해 둡니다.

그리고 검사는 한 겹이 아니라 세 겹으로 생각하면 좋아요.

경계, 도메인, DB 세 겹의 입력 방어

인젝션: 입력이 명령이 되는 순간

게시판 검색 API가 사용자가 보낸 검색어를 쿼리 문자열 사이에 그대로 이어 붙여 SQL을 만든다고 해 볼게요. 평소엔 잘 동작합니다. 그런데 검색어 자리에 [공격 입력 예시]처럼 SQL 조각을 섞어 보내면, DB는 그 일부를 데이터가 아니라 명령의 일부로 읽어요. 조건이 항상 참이 되면 전체 게시글이, 경우에 따라선 다른 테이블까지 나갑니다.

입력을 이어 붙일 때와 값으로 전달할 때의 차이

방어의 핵심은 쿼리의 모양을 먼저 고정하고, 입력은 값 자리에만 넣는 거예요. 이걸 파라미터 바인딩이라고 합니다. 빈칸이 뚫린 서식 종이를 먼저 인쇄해 두고, 사용자는 빈칸만 채울 수 있게 하는 것과 같아요. 빈칸에 무엇을 적든 서식 자체는 바뀌지 않습니다.

이 원리는 SQL에만 해당하지 않아요.

  • 명령 인젝션: 입력이 셸 명령 문자열에 들어가면, 셸은 특정 기호를 만나 다음 명령을 이어서 실행합니다.
  • 경로 조작: 파일 이름 입력에 상위 폴더로 올라가는 표현이 섞이면, 허용한 폴더 밖의 시스템 파일이 열립니다.
  • NoSQL 인젝션: 따옴표 하나 없이도, 문자열 자리에 객체가 들어오면 조회 조건이 바뀝니다.

ORM을 쓴다고 안전한 것도 아니에요. ORM 위에서도 쿼리를 문자열로 이어 붙이면 똑같이 뚫립니다. 기억할 한 줄은 이것입니다. 쿼리와 명령은 문자열로 조립하지 않는다.

파일 업로드: 이미지인 척하는 스크립트

프로필 사진 업로드도 입력이에요. 그것도 아주 큰 입력이죠.

파일 업로드의 정상, 공격, 방어 흐름

공격자는 이미지 헤더로 시작하지만 뒤에 서버에서 실행되는 코드가 붙은 파일을 만들어, 이미지라고 적어서 올립니다. 서버가 확장자와 Content-Type 헤더만 믿고, 원래 파일 이름 그대로 웹 루트에 저장한다면? 그 파일 주소를 여는 순간 서버에서 코드가 실행돼요. 이른바 웹셸입니다.

원리 수준의 방어는 네 가지예요. 내용으로 실제 형식을 판별하고, 저장 이름은 서버가 새로 정하고, 웹 루트 밖에 저장하고, 내려줄 때는 실행이 아니라 다운로드로 응답합니다.

정리

  • 서버에 도착한 입력은 언제든 조작될 수 있다. 화면 제약은 보안이 아니다.
  • 기본은 허용 목록, 쿼리와 명령은 문자열로 조립하지 않는다.
  • 업로드 파일은 이름도, 헤더도 믿지 않는다. 내용으로 판별하고 실행되지 않는 곳에 둔다.

강의에서는 이걸 직접 공격하고 고쳐 봅니다

섹션 2에서는 일부러 취약하게 만든 예제 서비스에 SQL·NoSQL 인젝션, 명령 인젝션, 경로 조작, 위장 파일 업로드를 직접 재현합니다.

  • Spring Boot와 Express 양쪽에서 같은 취약점을 고치는 코드
  • 고친 공격을 테스트 코드로 남겨, 리팩터링으로 되살아나지 않게 CI에서 막기
  • 역직렬화처럼 눈에 덜 띄는 공격과 OWASP 목록 읽는 법

강의 보러 가기: https://inf.run/XvwyH


profile
고인물 개발자(OG)

0개의 댓글