GET 요청이 서버에서 데이터를 변경하지 않아야하는 이유는 무엇입니까?


109

인터넷을 통해 다음과 같은 조언을 봅니다.

GET은 서버의 데이터를 변경해서는 안됩니다. POST 요청을 사용하십시오.

이 아이디어의 기초는 무엇입니까?

데이터베이스에 데이터를 삽입하고 GET 쿼리 문자열에 매개 변수를 전달하는 PHP 서비스를 만들면 왜 그럴까요? (SQL 주입을 처리하기 위해 준비된 명령문을 사용하고 있습니다). POST 요청이 더 안전한가요?

아니면 이것에 대한 역사적인 이유가 있습니까? 그렇다면 오늘이 조언이 얼마나 유효합니까?




이 질문을 해주셔서 감사합니다. @Oded 잘 표현 된 답변을 보내 주셔서 감사합니다. 나는 항상이 질문을하는 사람들을 보내기 위해 참고가 필요했습니다 :)
Benjamin Gruenbaum

또한 HTTP의 PUT를 참조 - stackoverflow.com/questions/630453/put-vs-post-in-rest (인 나무 등 약 노트)
Bratch

2
@JoachimSauer GET이 크롤러에서 파일을 저장했지만 근본적인 문제는 인증이 부족했습니다. 모든 스크립트 키디는 그들을 망각으로 게시 할 수 있습니다.
코드 InChaos

답변:


185

이것은 조언이 아닙니다.

A GET는 이러한 방식으로 HTTP 프로토콜 에서 정의됩니다 . 그것은 dem 등하안전해야 합니다.

이유는- GET캐시하고 브라우저에 새로 고칠 수 있습니다. 반복해서.

이것은 GET다시 동일하게 만들면 데이터베이스에 다시 삽입 한다는 것을 의미 합니다 .

GET링크가되고 검색 엔진에 의해 크롤링되는 경우 이것이 무엇을 의미하는지 고려하십시오 . 데이터베이스에 중복 데이터가 가득 차게됩니다.

또한 URI, 주소 지정 기능 및 HTTP GET 및 POST 사용을 제안 합니다 .


일부 브라우저 에서는 링크 프리 페치 에 문제가 있습니다 . 페이지 작성자가 표시하지 않더라도 프리 페치 링크를 호출합니다.

예를 들어, 로그 아웃이 사이트의 모든 페이지에서 링크 된 "GET"뒤에 있으면 사람들은이 동작으로 인해 로그 아웃 될 수 있습니다.


35
많은, 많은, 많은 도구, 유틸리티, 웹 크롤러 및 기타 것들이 GET결코 파괴적인 행동이 아니라고 가정합니다 . 해당 사양을 위반하여 응용 프로그램을 중단 한 경우 응용 프로그램의 두 부분을 모두 유지해야합니다.
Joachim Sauer

7
@ NimChimpsky :에 의해 변경됩니다 GET. 그 조언은 단순히 잘못되었습니다. 안전 은 부작용을 초래할 수있는 것이 아니라 사용자가 부작용에 대해 책임을 질 수 없음을 의미합니다. 그렇지 않으면 서버에 대한 로그 파일을 가질 수 없었습니다. 이것은 RFC2616의 섹션 9.1.1에서 아주 명확하게 설명되어 있습니다.
Jörg W Mittag

8
@ JörgWMittag : "단순히 틀렸다"고 말하지 않았고 "불완전하게 표현되었습니다"라고 말하고 싶습니다. GET은 목표이므로 변경되지 않아야합니다. 물론 GET 요청을 계산, 기록 및 관찰 할 수 있습니다. 그러나 실제 비즈니스 데이터를 수정해서는 안됩니다.
Joachim Sauer 2014 년

23
@NimChimpsky A GET는에 의해 요청 된 리소스를 변경해서는 안되지만 GET'서버의 아무것도 변경해서는 안된다'는 의미는 아닙니다. 물론 로그, 카운터 및 기타 서버 상태와 같은 사항은 요청 중에 변경 될 수 있습니다.
Eric King

8
몇 년 전 Google은 링크를 통해 페이지를 미리 가져 오는 브라우저 애드온 (iirc)을 출시했습니다. 이것은 잘못 설계된 일부 제어판에서도 발생했습니다. URL로 인해 레코드 나 서버에서 서버에 기록 또는 무언가가 기록되거나 삭제 될 수 있습니다 (post? action = delete). 이로 인해 사용자가 모르게 작업이 실행되었습니다. Google은 GET을 사용하여 상태를 변경 한 웹앱 제조업체의 결함 인 경우에도 iirc라는 애드온을 중단했습니다.
크 툴후

24

각 HTTP 동사는 자체 책임이 있습니다. 예를 들어 RFC에서GET 정의한대로

요청 -URI에 의해 식별되는 모든 정보 (엔티티 형태)를 검색하는 것을 의미합니다.

POST반면에, 공식적으로 삽입하거나 더 공식적으로 의미합니다

POST 메소드는 오리진 서버
가 요청에 포함 된 엔티티를
요청 라인의 Request-URI에 의해 식별 된 자원의 새로운 하위 항목으로 승인하도록 요청하는 데 사용됩니다.

이런 식으로 유지하는 이유 :

  • 매우 간단하며 1991 년 이후 전세계 인터넷 규모에서 작동합니다.
  • 단일 책임 원칙을 고수
  • 다른 당사자 GET는 정보 검색 및 데이터 마이닝 수단으로 사용
  • GET은 리소스 상태를 절대 수정하지 않는 안전한 작업으로 간주됩니다.
  • 보안 고려 사항 GET은 실제로는 읽기 이지만 POST실제로는 쓰기입니다.
  • GET은 브라우저, 네트워크의 노드, 인터넷 서비스 제공 업체에 의해 캐시됩니다.
  • 내용이 변경되지 않는 한 GET동일한 URL로 변경 하면 모든 사용자에게 동일한 결과가 반환되어야합니다.

완전성을 위해 올바른 사용법 (소스) 을 시행하십시오 .

  • GET매개 변수는 URL의 일부로 전달되며 기본적으로 작고 제한된 길이는 256 자이며 일부 서버는 4000 자 이상을 지원합니다. 긴 레코드를 삽입하려면이 데이터를 전달할 수있는 합법적 인 방법이 없습니다
  • 때 사용하는 보안 연결, ̶ 같은 TLS, ̶ URL을하지 얻기 암호화, ̶ 따라서 모든 매개 변수의 ̶ ̶G̶E̶T̶̶ 있습니다 전송 일반 텍스트. URL은 실제로 TLS로 암호화되므로 TLS가 좋습니다.
  • 이진 데이터 또는 비 ASCII 문자를 사용하여 삽입하는 GET것은 실용적이지 않습니다.
  • GET 사용자가 브라우저에서 뒤로 버튼을 누르면 다시 실행됩니다.
  • 일부 오래된 크롤러는 ?내부 에 기호 가있는 URL을 색인 생성하지 않을 수 있습니다

1
URL이 TLS를 통해 암호화되지 않았습니까? HTTP 헤더를 전송하기 전에 SSL / TLS 핸드 셰이크가 발생한다는 인상을 받았습니다. 이것이 단일 IP 주소를 통한 가상 호스팅 HTTPS 사이트가 어려운 이유입니다. 내가 착각 했니?
Brandon

맞아, 내가 고쳤다
oleksii

2
@Brandon 최신 브라우저는 IP 주소 당 하나 이상의 도메인을 호스트 할 수 있도록 호스트 도메인을 TLS 핸드 셰이크 (서버 이름 표시라고도 함)의 일부로 명확하게 보냅니다. URL의 경로 / 쿼리 부분은 TLS로 보호됩니다. 이와 관련하여 GET과 다른 HTTP 동사에는 차이가 없습니다.
코드 InChaos

9

편집 : 전에, POST는 CSRF로부터 당신을 보호하는 데 도움이되지만 이것이 잘못되었습니다. 나는 이것을 올바르게 생각하지 않았다. CSRF로부터 보호하기 위해 데이터를 변경하려면 모든 요청에 ​​세션 범위 고유의 숨겨진 토큰이 필요합니다.

인터넷 초기에는 브라우저 가속기가있었습니다. 이러한 프로그램은 페이지에서 링크를 클릭하여 컨텐츠를 캐시하기 시작합니다. Google Web Accelerator 는 이러한 프로그램 중 하나입니다. 이로 인해 링크를 클릭 할 때 변경되는 응용 프로그램이 혼란에 빠질 수 있습니다. 나는 여전히 가속기 소프트웨어를 사용하는 사람들이 있다고 가정합니다.

프록시 서버와 브라우저는 GET 요청을 캐시하므로 사용자가 페이지에 다시 액세스 할 때 요청을 애플리케이션으로 보내지 않아 사용자가 조치를 취했다고 생각하지만 실제로는 그렇지 않습니다.


1
CSRF는 GET 및 POST와 동일하게 가능합니다. 예를 들어 공격자는 사이트에 자동 제출 양식을 포함시켜 POST 요청을 트리거 할 수 있습니다. CSRF를 방지하기위한 표준 접근 방식은 요청에 암시 적으로 쿠키 헤더를 포함하는 것과 달리 공격자가 알 수없는 값을 명시 적으로 포함하는 것입니다.
코드 InChaos

8

데이터베이스에 데이터를 삽입하고 GET 쿼리 문자열에 매개 변수를 전달하는 PHP 서비스를 만들면 왜 그럴까요?

가장 간단한 대답은 "그게 GET의미가 없기 때문 "입니다.

사용 GET"- NOW ACT SPECIAL OFFER!"를 업데이 트에 대한 데이터를 전달하는 것은 사랑의 편지를 작성하고 봉투에 보내기 같다 표시된 두 경우 모두 수신자 및 / 또는 중개인이 메시지를 잘못 처리하는 것에 놀라지 않아야합니다 .


5

당신을 위해 CRUD의 데이터베이스 중심의 응용 프로그램에서 작업 다음 스키마를 사용 :

읽기 작업에 HTTP GET 사용 (SQL SELECT)

업데이트 작업에 HTTP PUT 사용 (SQL UPDATE)

작성 조작에 HTTP POST 사용 (SQL INSERT)

삭제 조작에 HTTP DELETE 사용 (SQL DELETE)


3
풋 vs 포스트는 당신이 말하는 것과 다릅니다. Put은 클라이언트가 정확한 위치에서 리소스를 수정할 때 사용됩니다. 게시물의 경우 서버는 궁극적으로 리소스에 대한 정확한 Uri를 결정합니다.
Andy

HTTP PUT이 UPDATE가 아닌 SQL DELETE 및 INSERT와 비슷하지 않습니까? 또한 SQL UPDATE는 한 번에 많은 레코드를 업데이트 할 수 있지만 HTTP PUT은 한 가지만 업데이트합니다.
Backwards_Dave

0

GET은 서버의 데이터를 변경해서는 안됩니다. POST 요청을 사용하십시오.

그 조언과 여기의 모든 대답이 잘못되었습니다. 분명히 나는 ​​극적으로 극적이며 다른 답변은 훌륭하지만 정확한 조언은 다음과 같이 주어져야한다고 생각합니다.

GET은 서버의 데이터를 거의 변경 하지 않아야 합니다. POST 요청을 사용하십시오.

"never"는 너무 극단적이라고 말하고, 여기에있는 다른 답변은 왜 "드물게"해야 하는지를 정확하게 설명하지만, GET으로 데이터를 변경하는 것이 합리적 일 수있는 몇 가지 시나리오가 있습니다. 예를 들어 일회용 이메일 확인 링크가 있습니다. 일반적으로 이러한 링크에는 액세스 할 때 데이터를 변경해야하는 GUID가 포함되어 있습니다. 올바르게 구현되면 후속 동일한 GET 요청이 무시됩니다.

이것은 분명히 엣지 케이스이지만 확실히 주목할 가치가 있습니다.


3
메일 클라이언트가 링크를 클릭하지 않고 링크를 가져 오려면 어떻게해야합니까? 예를 들어 악성 코드를 검사하려고하기 때문입니다. 수신 거부 링크에 대한 올바른 접근 방식은 사용자가 버튼을 클릭하여 수신 거부 할 수있는 페이지 (버튼 클릭이 POST 요청을 트리거하는 페이지)로 연결하는 것입니다.
코드 InChaos

@CodesInChaos-훌륭한 포인트! 동의합니다. 수신 거부 예를 제거하고 이메일 확인을 유일한 예로 남겨 두었습니다. GET이 의미가있는 이메일 확인 외에 다른 것이있을 수 있지만 지금은 생각할 수 없습니다.
TTT

GET에 부작용이있는 문제는 이메일 확인에도 동일하게 적용됩니다. 이제 링크를 따라가는 고객은 다른 사람이 사용자의 전자 메일을 사용하여 만든 계정을 확인하여 자신을 가장 할 수 있습니다.
코드 InChaos

@CodesInChaos-스트레칭입니다. 귀하가 말한 명의 도용은 동일한 이메일 주소가 아닌 동일한 사용자 이름 또는 공개 개인 이름에서 왔으며, 사용하는 이메일 주소에 관계없이 발생할 수 있습니다 (일반적으로 서버 만 계정 소유자의 이메일 주소를 알고 있음). 또한 다른 사람의 이메일 주소로 계정을 만드는 것은 의미가 없습니다. 어떻게 도움이 될 수 있습니까? 그들은 자신의 계정을 통제 할 수 없었습니다.
TTT
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.