상세 컨텐츠

본문 제목

서버가 요청을 거부했는데 403이 아닌 404를 반환하는 진짜 이유

생활용품

by ideas20748 2026. 7. 17. 02:31

본문

API를 개발하다 보면 한 번쯤 이 상황을 마주친다. 서버가 요청을 분명히 거부했는데, 응답 코드는 403이 아니라 404다. 처음 보면 "이거 잘못 구현한 거 아닌가?" 싶지만, 실제로는 의도된 설계 판단이다. 403과 404 중 무엇을 반환할지는 스펙 암기의 문제가 아니라, 리소스를 어떻게 보호할 것인지의 판단 문제다.

403을 반환하면 생기는 문제, 뭔지 알고 있나

서버가 요청을 거부했는데 403이 아닌 404를 반환하는 진짜 이유

HTTP 상태 코드 403은 "요청 자체는 이해했지만, 너에게 권한이 없다"는 의미다. 이걸 반환하면 클라이언트 입장에서는 한 가지 정보를 자동으로 얻게 된다. 바로 "이 리소스는 존재한다"는 사실이다.


권한만 없는 거니까, 권한을 어떻게든 우회하거나 다른 방식으로 접근을 시도해볼 여지가 생긴다. 서버 입장에서는 리소스의 존재 자체를 공개하지 않고 싶은데, 403을 반환하는 순간 그 정보가 노출된다.


이걸 막는 방법이 바로 404를 반환하는 것이다. 클라이언트에게 "그런 리소스 자체가 없어"라고 응답하면, 해당 리소스가 존재하는지 여부조차 알 수 없게 된다. 리소스의 존재 여부 자체를 숨기고 싶을 때, 403 대신 404를 반환하는 게 보안 측면에서 더 효과적이다.


비유로 이해하는 403 vs 404 차이

컴퓨터 바탕화면에 이상한 이름의 폴더가 하나 보인다고 가정해보자. 클릭했더니 비밀번호를 요구한다. 이 상황에서 보는 사람은 "이 폴더는 존재하고, 비밀번호만 알면 열 수 있겠구나"를 바로 인지한다. 이게 403과 같다.


반면 그 폴더가 숨김 처리되어 있어서 바탕화면에 아예 보이지 않는다면? 클릭 자체가 불가능하고, 뭔가 있는지조차 모른다. 이게 404 반환의 효과다.


서버가 특정 리소스를 완전히 숨기고 싶을 때, 비밀번호를 걸어두는 것(403)보다 폴더 자체를 보이지 않게 하는 것(404)이 더 강한 보호다. 민감한 리소스일수록 존재 여부 자체를 드러내지 않는 게 유리하다.


GitHub도 같은 이유로 404를 반환한다

이게 개인 취향이나 특이한 구현이 아니라는 증거가 있다. GitHub은 프라이빗 레포지토리에 멤버가 아닌 사용자가 접근했을 때 403이 아니라 404 페이지를 보여준다.


실제로 많은 개발자들이 "왜 403이 아니라 404냐"고 GitHub 측에 문의했고, GitHub은 공식 개발자 문서에 그 이유를 명확하게 써놨다. 요약하면 이렇다.


403을 반환하면 프라이빗 레포지토리가 존재한다는 사실을 유추할 수 있기 때문에, 레포지토리 존재 여부를 클라이언트가 알지 못하게 하기 위해 404를 반환한다.


스펙을 어기거나 실수한 게 아니다. 리소스 보호 목적으로 의도적으로 선택한 응답 코드다. 403을 반환했을 때 생기는 추가적인 접근 시도를 원천 차단하기 위한 설계다.


반대 방향의 사례, 리소스가 없어도 404 대신 200을 반환하는 경우

HTTP 상태 코드를 스펙대로만 쓰지 않는 사례는 이것만이 아니다. 반대 방향도 있다. 리소스가 존재하지 않는 상황인데 404가 아닌 200이나 204를 반환하는 경우다.


예를 들어, 특정 채널의 구독자 목록을 요청했는데 구독자가 한 명도 없는 상태라고 해보자. 이때 서버가 404를 반환하면 클라이언트는 400번대 응답이니까 에러 핸들러를 태운다. 그런데 클라이언트 입장에서는 구독자가 있든 없든 에러가 아니라, 있으면 화면에 뿌리고 없으면 0을 출력하고 싶었던 것뿐이다.


이 상황에서 404를 반환하면 클라이언트와 서버 간의 의도가 어긋난다. 구독자가 없다는 건 에러가 아니라 정상적인 빈 상태다.


이럴 때는 200을 반환하면서 빈 배열을 넘기거나, 204(No Content)를 반환하고 클라이언트 쪽에서 204가 왔을 때 빈 배열로 처리하도록 규약을 맞추는 게 더 맞는 설계다. 리소스의 속성이 null인지 빈 배열인지에 따라서 응답 코드 선택도 달라진다.


그래서 HTTP 상태 코드는 어떤 기준으로 선택해야 하나

핵심은 스펙을 외우는 게 아니라, 상황을 판단하는 것이다. HTTP 상태 코드는 스펙에 정의된 용도 그대로만 쓰는 것보다, 구현하려는 기능의 성격과 리소스 반환값의 형태에 따라 선택하는 게 더 효과적인 API 설계다.


체크해볼 기준은 이렇다.


첫째, 리소스의 존재 자체를 감춰야 하는 보안 요구사항이 있는가. 있다면 권한 거부 상황에서도 404를 고려할 수 있다.


둘째, 클라이언트가 이 응답을 에러로 처리할 것인가, 데이터 상태로 처리할 것인가. 데이터 상태라면 400번대 코드보다 200이나 204가 더 적합하다.


셋째, 서버와 클라이언트 간의 규약이 명확하게 맞춰져 있는가. 표준을 벗어난 응답 코드를 쓰더라도, 팀 내에서 그 의미가 명확히 공유되어 있어야 한다.


막상 API를 설계하다 보면, 교과서적으로 "이건 403이지"라고 딱 떨어지지 않는 상황이 꽤 많다. 생각보다 상태 코드 하나가 클라이언트 동작 전체에 영향을 미친다. 좋은 API 설계는 스펙 준수가 아니라, 서버와 클라이언트 간의 오해를 줄이는 것이다.


더 많은 생활·인테리어·건축 정보는 kooreea.com에서 확인하세요.

관련글 더보기