GET 요청에 body를 담아서 주세요!
GET Method 에는 Body를 못담지 않나요?
발견오류
사실 오류라고 할 순 없지만, 프로젝트 과정에서 만난 문제라고 판단되어 글로 작성하게 되었습니다.
백엔드 측에서 GET 요청에 사용자 권한인증을 위해 body를 담아서 보내달라는 API를 만들었습니다.
..? GET 요청에는 body를 못담을텐데?
지금까지 제가 알기론 body를 담지 못하는것이 GET 요청의 특징 중 하나인 것으로 알고있었습니다.
하지만 제가 알고있는 내용이 팀원을 설득시킬 수 있을만큼 정확하지 않고 정리되지 않은 정보였기에 제가 잘못알고 있던 것이라면 제대로 알기위해,
팀원이 잘못알고 있던 것이라면 정확한 근거를 바탕으로 설득하기 위해 더욱 정확히 알아봐야겠다는 생각이 들었습니다.
GET 과 Body
충격적인 사실(이자 오늘의 결론) : GET 요청에는 body를 담을 수 있다.
GET 요청에도 Body를 담을 수 있습니다.
조금 더 엄밀히 얘기하자면, 가능은 합니다.
현재 가장 많이 사용되는 HTTP 버전인 1.1 버전의 공식문서에선 GET method의 body 사용에 대해서 금지하는 내용이 빠져있습니다.
그 부분은 많은 해석의 여지를 남기지만, GET 메서드에 body를 담는것이 규칙상 불가능하지 않다는 뜻이 됩니다.
GET 과 POST 의 차이
일반적으로 각각의 HTTP Method 에 대해 배울 때, 우리는 다음과 같이 배우곤 합니다.
- GET
- 데이터를 검색하거나 서버에 정보를 요청하는 데이터를 읽은 작업을 할 때 사용합니다.
일반적으로 요청 데이터를 URL 파라미터로 포함하여 요청하며 URL 길이에는 제한이 있으므로 전송할 수 있는 데이터에 제한이 있습니다. 또한 URL에 데이터가 노출되기 때문에 중요한 정보를 전송하기엔 부적절합니다. - POST
- 서버에 데이터를 제출하는 등 데이터를 서버에 생성하거나 업데이트할 때 주로 사용됩니다. 일반적으로 데이터를 HTTP body에 담아서 전송합니다.
- 두 Method의 차이점
- GET 요청은 데이터를 검색하는데, POST 는 데이터 제출에 사용되며,
설명에 따라 GET 요청은 요청 데이터를 URL 파라미터에 담고, POST는 body에 담습니다.
GET은 전송할 수 있는 데이터에 제한이 있으며 보안상 비교적 불안전합니다.
POST 는 전송할 수 있는 데이터에 제한이 없으며 보안상 비교적 안전합니다.
위 내용과 유사하게 공부하신 분이 적지 않을 것이라고 생각합니다. 하지만 엄밀히 말하자면 이는 절반은 맞고 절반은 틀린 내용입니다. 아마도 가르치는 입장에서 이분적으로 설명하는것이 이해하고 외우기에 더 적절해서 이렇게 나누지 않았을까 싶습니다.
위 내용에서 정확하지 않은 부분들은 다음과 같으며 이 내용들을 중심으로 글을 이어나가보겠습니다.
- GET 요청엔 body를 담을 수 없다. ( 사실 담을 수 없다고는 안했지만 오해의 소지가 충분하니… )
- POST 요청이 보안상 더 안전하다.
GET 요청엔 Body 를 담을 수 없다.
앞서 우리는 충격적인 사실을 통해 GET 요청에도 Body 를 담을 수 있다는 정보를 알게 되었습니다.
실제로 백엔드 팀원이 이런 오류를 범한 이유도 POSTMAN을 사용한다면 GET 요청에 BODY를 담을 수 있기 때문입니다.
또한 앞서 HTTP 1.1 버전의 공식문서에서도 명시적으로 금지하는 내용이 없었기에 우선 가불을 얘기하자면, 불가능하진 않습니다.
하지만 Client의 종류와 버전마다 지원여부가 달라지기 때문에 사용하지 않는것이 바람직 해 보입니다.
이 문제의 발단인 프로젝트에서 팀원이 GET Method의 body에 담고자 한 내용은 바로 사용자 권한인증에 필요한 Access Token이었습니다.
그렇다면 어쨌든, GET Method에서도 Body를 사용할 수 있는데 왜 일반적으론 사용하지 않을까요?
REST API
알고계셨나요? : GET 요청은 캐싱이 가능하며 브라우저 히스토리에 남습니다! MDN - HTTP 캐싱
많은 경우 API를 구현할 때 RESTful API를 따르곤 합니다.
여기서 REST 설계는 HTTP 프로토콜의 주요 설계자 중 한명인 로이 필딩이 제안한 설계원칙입니다.
간단하게 요약하자면, 세계에서 HTTP 프로토콜을 가장 잘 아는 사람이 제안한 HTTP 프로토콜의 장점을 살려 잘 활용하기 위해 제안한 아키텍처 스타일이라고 이해하면 될 것 같습니다. 그 요소들 중 하나가 바로 캐시 가능성(Cacheability) 입니다.
알고계셨나요? 에서 확인하셨듯이, 사실 GET 요청은 캐싱이 가능합니다. 따라서 멱등성을 보장할 때 GET 요청의 효율성은 극대화됩니다.
하지만 body를 담아 보낼 경우 URL을 캐시키로 사용하는 GET 요청은 멱등성이 보장되지 않으며, 따라서 캐시기능을 활용할 수 없게 됩니다.
따라서 GET 요청에 Body를 담아서 얻은 것 보다는, 캐시를 활용하는 것이 더 크기 때문에 body를 사용하지 않는것이 조금 더 권장된다고 볼 수 있겠습니다.
POST 요청이 보안상 더 안전하다.
이것은 제가 겪은 GET 요청의 URL에 Access Token을 담는 문제와도 일부 연결됩니다. 흔히 POST 요청이 여러가지 데이터를 body에 담아서 보내기 때문에 비교적 더 안전하고, GET 요청은 URL 에 모든 요청정보가 노출되기 때문에 보안상 취약하다고 공부합니다. 하지만 사실상 틀렸습니다. 공격자가 사용자의 요청 URL을 확인하기 위해선 패킷이나 데이터를 탈취해야합니다.
그러나 패킷 혹은 데이터를 탈취당한 순간 모든 정보를 들여다볼 수 있기 때문에 URL 에 요청정보를 노출하거나, body에 데이터를 담는것은 아무 의미가 없게 됩니다.
‘URL이 아닌 body에 담아두었기 때문에 공격자가 귀찮아서 들여다보지 않는다’ 라는 경우의 수를 생각하는 게 아니라면 일반적으로 우리가 공부한 [ POST 가 보안상 더 안전하다 ] 라는 내용은 옳지 못하며 보안을 유지하기 위해선 HTTPS와 같은 암호화 과정이 필수적으로 필요합니다.
결론
이미 HTTPS 프로토콜을 쓰는 우리 서비스에서 보안상의 이유로 GET 요청에 body를 쓰는건 큰 의미가 없고 오히려 GET 요청에 제공되는 캐싱이라는 강력한 기능을 포기하는 아쉬운 선택이다.
