안전한 메서드
고친 사람 github-actions[bot]
안전한 메서드는 서버에 있는 것을 읽기만 하겠다고 미리 밝히는 요청 방식입니다. 이 약속이 있어서 브라우저와 검색 로봇은 사람에게 묻지 않고도 요청을 보냅니다. GET 이 대표입니다.
쉽고 빠른 이해
안전한 메서드는 서버의 상태를 바꾸지 않는 요청 방식입니다. 게시글을 읽어 오는 GET 요청이 그렇습니다.
이 구분이 없으면 사람 대신 요청을 보내는 프로그램이 무엇을 눌러도 되는지 알 수 없습니다. 검색 로봇은 링크를 찾는 대로 따라가고, 브라우저는 다음에 볼 것 같은 화면을 미리 받아 둡니다.
어떻게 도나:
- 클라이언트가 읽기만 하는 메서드를 골라 보냅니다
- 서버는 그 요청으로 데이터를 바꾸지 않습니다
- 중간의 캐시나 검색 로봇은 이 약속을 믿고 요청을 마음껏 보냅니다
대가도 있습니다. 안전은 기계가 강제하는 규칙이 아니라 서버를 만드는 사람이 지키는 약속이라, 읽기 요청 안에 데이터를 지우는 코드를 넣어도 아무도 막아 주지 않습니다.
상세
도서관에서 책을 꺼내 읽고 제자리에 꽂아 두면 서가는 그대로입니다. 대출 창구에 책을 내밀면 대출 기록이 남고 그 책은 한동안 서가에서 빠집니다. 안전한 메서드는 앞쪽, 열람에 해당합니다.
HTTP(HyperText Transfer Protocol, 하이퍼텍스트 전송 프로토콜) 요청은 맨 앞에 요청 메서드를 하나 답니다. 요청 메서드는 서버에게 무엇을 해 달라는 요청인지 알리는 낱말입니다. 객체에 딸린 함수를 부르는 프로그래밍 언어의 메서드와는 다른 말입니다.
어떤 메서드의 뜻이 본래 읽기 전용이면 그 메서드는 안전합니다. 안전한 메서드를 보낸 클라이언트는 서버의 상태가 바뀌기를 요청하지 않았고, 바뀌리라 기대하지도 않습니다.
어느 메서드가 안전한가
메서드는 이름마다 뜻이 미리 정해져 있습니다. 그래서 안전한지 아닌지도 이름만 보면 갈립니다.
| 메서드 | 뜻 | 안전 |
|---|---|---|
| GET | 대상을 읽어 옵니다 | ✓ |
| HEAD | 본문 없이 머리말만 읽어 옵니다 | ✓ |
OPTIONS |
그 대상에 무엇을 할 수 있는지 묻습니다 | ✓ |
TRACE |
요청이 어떤 경로로 도착했는지 되돌려 받습니다 | ✓ |
| POST | 보낸 것을 서버가 처리하게 합니다 | ✗ |
| PUT | 대상을 보낸 것으로 통째로 바꿉니다 | ✗ |
| PATCH | 대상의 일부를 고칩니다 | ✗ |
| DELETE | 대상을 지웁니다 | ✗ |
아래 넷을 안전하지 않은 메서드라고 부릅니다. 이 넷은 서버에 무언가를 남기거나 지우는 것이 원래 뜻이라 사람이 뜻을 갖고 누른 동작에서만 나가야 합니다.
안전한 메서드가 남기는 흔적
안전한 메서드를 받아도 서버 안에서는 무언가가 바뀝니다. 대부분의 서버는 요청이 끝날 때마다 접근 로그에 한 줄을 덧붙입니다. 게시글을 읽을 때 조회수를 하나 올리는 서비스도 흔합니다.
이런 변화가 있어도 그 요청은 여전히 안전한 것으로 봅니다. 기준은 서버가 무엇도 안 바꾸느냐가 아니라, 클라이언트가 그 변화를 주문했고 그에 대한 책임을 지느냐입니다. 조회수를 올려 달라고 부탁한 적이 없으니 책임도 클라이언트에게 없습니다.
그래서 안전은 서버 코드가 저절로 지켜 주는 성질이 아니라 API(Application Programming Interface, 애플리케이션 프로그래밍 인터페이스)를 설계하는 사람이 지키는 약속입니다. 읽기 요청을 받아 데이터를 지우는 코드를 짜도 웹 서버는 그것을 막지 않습니다.
안전을 믿고 도는 프로그램
메서드를 안전한 것과 그렇지 않은 것으로 가르는 까닭은 사람이 누르지 않은 요청 때문입니다. 이 구분이 없으면 어떤 요청을 사람 대신 보내도 되는지 아무도 판정할 수 없습니다. 검색 엔진의 크롤러는 링크를 찾는 대로 따라가며 요청을 보냅니다. 사람이 한 번도 누르지 않은 요청이 수천 건 나갑니다.
브라우저도 비슷한 일을 합니다. 다음에 볼 것 같은 화면을 미리 받아 두는 프리페치가 그렇습니다. 링크 위에 마우스를 올리기만 해도 요청이 나가기도 합니다.
캐시도 이 약속 위에 섭니다. 캐시는 응답을 저장해 두었다가 같은 요청에 다시 내주는 장치입니다. 서버까지 가지 않고 저장본을 내줘도 되는 까닭은, 그 요청이 서버를 바꾸지 않는다는 것을 알기 때문입니다.
응답이 오지 않을 때 재시도하기도 부담이 없습니다. 읽기만 하는 요청은 몇 번을 더 보내도 서버에 쌓이는 것이 없습니다.
안전함과 멱등함의 차이
멱등하다는 것은 같은 요청을 여러 번 보내도 서버에 남는 결과가 한 번 보낸 것과 같다는 뜻입니다. 안전한 메서드는 애초에 서버를 바꾸지 않으므로 전부 멱등합니다. 거꾸로는 성립하지 않습니다.
| 메서드 | 안전 | 멱등 |
|---|---|---|
| GET | ✓ | ✓ |
| DELETE | ✗ | ✓ |
| POST | ✗ | ✗ |
가운데 줄이 거꾸로가 성립하지 않는 예입니다. 같은 글을 세 번 지워도 남는 결과는 「그 글이 없다」 하나라 DELETE 는 멱등하지만, 첫 요청이 서버를 바꾸었으므로 안전하지는 않습니다.
두 성질은 쓰임이 다릅니다. 멱등성은 답이 안 왔을 때 다시 보내도 되는지를 판정하고, 안전성은 사람이 시키지 않은 요청을 보내도 되는지를 판정합니다.
읽기 요청에 숨은 삭제
안전이 깨지는 가장 흔한 꼴은 삭제를 GET 으로 만드는 것입니다. /posts/42/delete 같은 주소를 링크로 걸어 두면 클릭 한 번으로 지워지니 만들기 간단합니다.
문제는 그 링크를 사람만 누르지 않는다는 것입니다. 크롤러가 목록 화면을 훑으면 삭제 링크까지 따라갑니다.
sequenceDiagram
participant 크롤러
participant 서버
크롤러->>서버: GET /posts
서버-->>크롤러: 글 목록과 삭제 링크
크롤러->>서버: GET /posts/42/delete
서버-->>크롤러: 200 OK
Note over 서버: 42번 글이 지워진다
그림은 크롤러가 목록을 읽고 거기 있던 링크를 따라가는 두 번의 요청을 보입니다. 크롤러는 규칙을 어긴 적이 없습니다. 안전하다고 약속된 메서드를 보냈을 뿐이고, 약속을 어긴 쪽은 서버입니다.
로그인한 사람만 보는 화면이라 괜찮다고 보기도 어렵습니다. 브라우저의 미리 읽기도, 채팅에 붙여 넣은 주소의 미리보기도 사람 대신 같은 요청을 보냅니다.
안전과 보안의 경계
「안전」이라는 말 때문에 도청이나 유출을 막아 준다고 읽기 쉽습니다. 안전한 메서드가 말하는 것은 서버의 상태 하나뿐입니다. 안전한 요청도 비밀번호를 주소에 실어 보내면 그대로 새어 나갑니다.
방향이 반대인 쓰임은 있습니다. 크로스 사이트 요청 위조는 다른 사이트가 사용자의 브라우저를 빌려 요청을 보내게 하는 공격입니다. 이 공격이 노리는 것은 서버를 바꾸는 요청이라, 브라우저의 방어 장치도 안전한 메서드와 그렇지 않은 메서드를 갈라 적용합니다.
관련 항목
안전한 메서드로 분류되는 요청 메서드
요청 메서드 · GET · HEAD · OPTIONS · TRACE
서버 상태를 바꾸는 요청 메서드
POST · PUT · PATCH · DELETE · 안전하지 않은 메서드
안전성과 같이 따지는 요청의 성질
멱등성 · 캐시 가능성 · 조건부 요청 · 재시도 · 부수 효과
이 약속을 믿고 요청을 보내는 프로그램
크롤러 · 프리페치 · 캐시 · 프록시 · 리버스 프록시
안전을 어겼을 때 터지는 문제
크로스 사이트 요청 위조 · 중복 요청 · 감사 로그 · 소프트 삭제
안전한 메서드를 정의하는 표준·문서
HTTP · RFC 9110 · HTTP 메서드 · HTTP/1.1
안전한 메서드가 쓰이는 설계 규약
다른 이름: safe method · 안전 메서드 · 메서드의 안전성