
이 글은 인프런 강의 「백엔드 개발자를 위한 서버 보안 실무」 섹션 4를 입문자용으로 풀어 쓴 글이에요.
내 프로필을 수정하는 API가 있어요. 화면에는 닉네임과 소개 글 칸만 있습니다. 서버 코드는 편하게 받은 요청 본문을 통째로 사용자 정보에 저장해요.
누군가 화면을 거치지 않고, 본문에 role 같은 필드를 하나 더 끼워 보냅니다. 서버는 받은 필드를 전부 반영하고, 다시 로그인한 그 사용자는 관리자 메뉴를 보게 돼요.
API는 이렇게 우리가 생각한 것보다 많은 걸 받아들이고, 많은 걸 내보냅니다. 이번 글에서는 API에서 특히 자주 터지는 다섯 가지를 봅니다.

받은 필드를 모두 복사하는 습관이 Mass assignment를 만들어요. 반대 방향도 있습니다. 저장된 객체를 통째로 응답하면 화면에 쓰지 않는 내부 필드(역할, 내부 메모, 해시 값 등)까지 함께 나가요. 앱 화면에서 숨겨도 응답에는 그대로 있습니다.
원칙은 요청도 응답도 허용 목록이에요. 받을 필드와 내보낼 필드를 미리 정해 두고, 모르는 필드가 오면 거절합니다.
모바일 앱도 같아요. 앱이 가격과 쿠폰 자격을 확인했더라도, 그 요청은 중간에서 고칠 수 있습니다. 금액과 자격은 서버가 다시 계산해야 해요.

게시판 본문에 스크립트가 숨겨진 태그를 쓰고, 서버가 그 본문을 HTML에 그대로 끼워 넣어 보여 준다고 해 볼게요. 브라우저는 그걸 글자가 아니라 태그로 읽고, 그 글을 여는 모든 사람의 브라우저에서 스크립트가 실행됩니다. 쿠키나 토큰이 공격자에게 넘어갈 수 있어요.
막는 자리는 입력이 아니라 출력하는 자리예요. 출력할 때 인코딩하고, 꼭 HTML을 허용해야 한다면 허용 태그만 남기도록 정화합니다. 여기에 CSP(어떤 스크립트만 실행될 수 있는지 브라우저에 알려 주는 보안 헤더)가 한 겹 더 막아 줘요. 그리고 토큰을 스크립트가 읽을 수 있는 저장소에 두면, XSS 한 번에 바로 읽힌다는 점도 기억해 두세요.

결제사가 "결제 완료"를 알려 주는 웹훅을 받는 API가 있어요. 보낸 사람을 확인하지 않는다면, 주소만 알면 누구든 돈을 내지 않고 결제 완료 이벤트를 꾸며 보낼 수 있습니다. 같은 요청을 몇 번이고 다시 보낼 수도 있고요.
확인할 건 세 가지예요. 서명(결제사와 나만 아는 비밀로 만든 값이 맞는가), 시각(몇 분 안에 보낸 요청인가), 이벤트 ID(이미 처리한 이벤트인가). 한 줄로 줄이면, 웹훅도 인증이 필요한 API입니다.
분당 요청 수를 IP 기준으로 제한해 두었는데, 서버가 클라이언트가 보낸 IP 관련 헤더를 무조건 믿는 설정이라면 어떨까요? 공격자는 요청마다 다른 값을 적어 제한을 무력화합니다. 신뢰할 프록시만 정확히 믿고, 로그인 사용자라면 사용자 기준으로 제한해야 해요.
반대로 네트워크가 끊겨 앱이 같은 주문 요청을 다시 보내면 주문이 두 개 생길 수 있어요. 같은 요청을 한 번만 처리하게 하는 멱등성 키가 이 문제를 풉니다.

둘 다 "다른 사이트"와 관련 있어서 자주 섞여요.
그래서 CORS를 아무리 잘 설정해도 CSRF는 따로 막아야 합니다. 쿠키의 SameSite 속성, CSRF 토큰, 요청 출처 확인이 그 역할을 해요.
강의에서는 이걸 직접 공격하고 고쳐 봅니다
섹션 4에서는 예제 서비스로 역할 필드 끼워 넣기, 게시판 XSS, 위조·재전송 웹훅, 헤더 위조로 요청 제한 우회, 다른 사이트에서 보내는 CSRF를 차례로 재현합니다.
- Spring Boot·Express 양쪽의 DTO 분리, 출력 인코딩, CSP nonce 적용 코드
- 웹훅 서명 검증과 재전송 방지, 멱등성 키 설계
- 각 공격이 다시 통하지 않는지 확인하는 테스트와 섹션 체크리스트
강의 보러 가기: https://inf.run/XvwyH