GETリクエストがサーバー上のデータを変更しないのはなぜですか?


109

インターネット全体で、次のアドバイスが表示されます。

GETはサーバー上のデータを変更してはいけません-そのためにPOSTリクエストを使用してください

この考えの根拠は何ですか?

データベースにデータを挿入するphpサービスを作成し、GETクエリ文字列でパラメーターを渡すと、なぜ間違っているのですか?(SQLインジェクションを処理するために、準備済みステートメントを使用しています)。POSTリクエストは何らかの方法でより安全ですか?

または、これには何らかの歴史的な理由がありますか?もしそうなら、このアドバイスは今日どのくらい有効ですか?




この質問をしていただきありがとうございます、と私はいつも:)に向けて、この質問をする人に送信するための基準を必要としますが、うまく言葉で表現答えを@Oded感謝
ベンジャミンGruenbaumを

HTTP PUTも参照してください-stackoverflow.com/questions/630453/put-vs-post-in-rest(i等性に関する注意事項を含む)
バッチ

2
@JoachimSauer GETはクローラーからそれらを保存しますが、根本的な問題は認証の欠如でした。どんなスクリプトキディも、それらを忘却の中にPOSTすることができます。
CodesInChaos

回答:


185

これはアドバイスではありません。

A GETHTTPプロトコルでこのように定義されます。それはdem等安全であることになっています。

理由については-をGETキャッシュしてブラウザで更新することができます。何度も何度も。

これは、同じものをGET再度作成すると、データベースに再度挿入することを意味します。

GETがリンクになり、検索エンジンによってクロールされる場合の意味を検討してください。データベースに重複データがいっぱいになります。

また、URIの読み取り、アドレス可能度、HTTP GETおよびPOSTの使用をお勧めします


一部のブラウザでは、リンクのプリフェッチに問題もあります。ページの作成者から指示されていなくても、リンクをプリフェッチするための呼び出しが行われます。

たとえば、ログアウトがサイトのすべてのページからリンクされた「GET」の背後にある場合、この振る舞いだけでログアウトできます。


35
多くの、多くの、多くのツール、ユーティリティ、Webクローラー、およびその他の事柄は、それGETが破壊的なアクションになることはないと想定しています(このように指定されているため)。その仕様を破ることによってアプリケーションを破った場合、アプリケーションの両方の部分を保持することになります。
ヨアヒムザウアー

7
@NimChimpsky:によって変更されますGET。そのアドバイスは単に間違っています。安全とは、副作用がないことではなく、ユーザーが副作用に対して責任を負うことができないことを意味します。そうしないと、サーバーのログファイルを取得できませんでした。これは、RFC2616のセクション9.1.1で明確に記述されています。
ヨルグWミットタグ

8
@JörgWMittag:「単純に間違っている」とは言いませんが、「不完全に表現されている」と言います。GETは目標であるため、変更はありません。もちろん、GETリクエストを数え、記録し、観察することができます。ただし、実際のビジネスデータは変更しないでください。
ヨアヒムザウアー

23
@NimChimpsky A GETは、によって要求されたリソースを変更すべきGETではありませんが、それは「サーバー上の何も変更すべきではない」という意味ではありません。もちろん、ログ、カウンター、その他のサーバーの状態などは、リクエスト中に変更される可能性があります。
エリックキング

8
かなり前に、Googleはリンク経由でページをプリフェッチするブラウザーアドオン(iirc)をリリースしました。これは、設計が不十分な一部のコントロールパネルでも発生しました。URLにより、レコードや何かがサーバー上で書き込まれたり、削除されることもあります(post?action = deleteを考えてください)。これにより、ユーザーが知らない間にアクションが実行されました。GETを使用して状態を変更することがwebappのメーカーのせいであったとしても、Googleはその理由であるiircを中止しました。
クトゥルフ

24

各HTTP動詞には独自の責任があります。たとえばGETRFCで定義されている

は、Request-URIによって識別される情報(エンティティの形式)を取得することを意味します。

POST、一方で、挿入またはより正式に

POSTメソッドは
、要求に含まれるエンティティを、要求
行のRequest-URIで識別されるリソースの新しい部下として受け入れることを要求するために使用されます。

このように保つ理由:

  • それは非常にシンプルで、1991年以来グローバルなインターネット規模で機能しています
  • 単一の責任原則に固執する
  • 他の関係者GETは、情報検索およびデータマイニングの手段として機能するために使用します
  • GETは、リソースの状態を決して変更しない安全な操作であると想定されます
  • セキュリティ上の考慮事項は、GET事実上読み取りですがPOST事実上は書き込みです
  • GETは、ブラウザー、ネットワーク内のノード、インターネットサービスプロバイダーによってキャッシュされます
  • コンテンツが変更されない限り、GET同じURLがすべてのユーザーに同じ結果を返す必要があります。そうしないと、返された結果でこれまでに何も信頼できなくなります。

完全を期し、正しい使用を強制するために(ソース)

  • GETパラメータはURLの一部として渡されます。これは、デフォルトで256文字の小さく制限された長さで、一部のサーバーは4000以上の文字をサポートしています。長いレコードを挿入する場合、このデータを渡す正当な方法はありません
  • とき使用して安全な接続、̶などTLS、̶URLではありません取得し、暗号化され、̶したがって、すべてTHEパラメータの̶ ̶G̶E̶T̶̶されている転送プレーンテキスト。URLは実際にはTLSで暗号化されているため、TLSは問題ありません。
  • を使用してバイナリデータまたは非ASCII文字を挿入するのGETは実用的ではありません
  • GET ユーザーがブラウザの[戻る]ボタンを押すと、再実行されます
  • 一部の古いクローラーは、?内部にサインがあるURLのインデックスを作成しない

1
URLはTLSで暗号化されていませんか?HTTPヘッダーが転送される前にSSL / TLSハンドシェイクが発生するという印象を受けました。これが、単一のIPアドレスでのHTTPSサイトの仮想ホスティングが難しい理由です。私は間違っていますか?
ブランドン

そうです、私はそれを修正しました
-oleksii

2
@Brandon Modernブラウザは、TLSハンドシェイク(サーバー名表示と呼ばれる)の一部としてホストドメインを平文で送信し、IPアドレスごとに複数のドメインをホストできるようにします。URLのパス/クエリ部分はTLSによって保護されています。この点に関して、GETと他のHTTP動詞の間に違いはありません。
-CodesInChaos

9

編集:以前、POSTはCSRFからあなたを守るのに役立つと言いましたが、これは間違っています。私はこれを正しく考えていませんでした。CSRFから保護するためにデータを変更するには、すべてのリクエストでセッションスコープの一意の非表示トークンが必要です。

インターネットの初期には、ブラウザアクセラレータがありました。これらのプログラムは、ページ上のリンクをクリックしてコンテンツをキャッシュし始めます。Google Web Acceleratorはこれらのプログラムの1つでした。これは、リンクがクリックされたときに変更を加えるアプリケーションに大混乱をもたらす可能性があります。アクセラレータソフトウェアを使用している人がまだいると思います。

プロキシサーバーとブラウザはGETリクエストをキャッシュするため、ユーザーが再びページにアクセスすると、アプリケーションにリクエストが送信されない可能性があるため、ユーザーはアクションを実行したと考えますが、実際にはしません。


1
CSRFは、GETとPOSTでも同様に可能です。たとえば、攻撃者は自分のサイトに自動送信フォームを含めて、POST要求をトリガーできます。CSRFを防ぐための標準的なアプローチは、リクエストに攻撃者が知らない値を明示的に含めることです(暗黙的にCookieヘッダーを含めるのとは異なります)。
CodesInChaos

8

データベースにデータを挿入するphpサービスを作成し、GETクエリ文字列でパラメーターを渡すと、なぜ間違っているのですか?

最も簡単な答えは、「それがGET意味するものではないから」です。

GET更新用のデータを渡すために使用することは、ラブレターを書いて、「特別オファー-今すぐ行動する!」と記された封筒に入れて送るようなものです。どちらの場合でも、受信者や仲介者がメッセージを誤って処理しても驚かないでください


5

あなたのためにCRUDのデータベース中心のアプリケーションでの操作次のスキーマを使用します。

読み取り操作にHTTP GETを使用する(SQL SELECT)

更新操作にHTTP PUTを使用する(SQL UPDATE)

作成操作にHTTP POSTを使用する(SQL INSERT)

削除操作にHTTP DELETEを使用(SQL DELETE)


3
Put vs Postは、あなたが述べている通りではありません。Putは、クライアントが指定された正確な場所でリソースを変更する場合に使用します。投稿の場合、サーバーは最終的にリソースへの正確なUriを決定します。
アンディ14年

HTTP PUTは、UPDATEではなくSQLのDELETEおよびINSERTに似ていますか?また、SQL UPDATEは一度に多くのレコードを更新できますが、HTTP PUTは1つのもののみを更新します。
Backwards_Dave

0

GETはサーバー上のデータを変更してはいけません-そのためにPOSTリクエストを使用してください

そのアドバイスと、ここでの答えはすべて間違っています。明らかに私は過度に劇的です、他の答えは素晴らしいですが、私は正確なアドバイスが与えられるべきであると信じています:

GETがサーバー上のデータを変更することほとんどありません。そのためにPOSTリクエストを使用してください

「決して」とは言いすぎです。ここの他の回答では、「まれに」行うべき理由を正確に説明していますが、GETでデータを変更することが完全に妥当なシナリオもあります。例として、1回限りのメール確認リンクがあります。通常、これらのリンクには、アクセス時にデータを変更する必要があるGUIDが含まれています。正しく実装された場合、後続の同一のGET要求は無視されます。

これは明らかにエッジケースですが、確かに注目に値します。


3
メールクライアントがクリックせずにリンクを取得することにした場合はどうなりますか?たとえば、マルウェアをスキャンするためです。購読解除リンクの適切なアプローチは、ユーザーがボタンをクリックして購読を解除できるページに移動することです(ボタンをクリックするとPOST要求がトリガーされます)。
CodesInChaos

@CodesInChaos-素晴らしい点!仰るとおりです。登録解除の例を削除し、メールの確認のみを唯一の例として残しました。GETが理にかなっている電子メール検証以外の方法もありますが、現時点では考えられません。
TTT

GETに副作用があるという問題は、電子メールの確認にも同様に当てはまります。リンクをたどるクライアントは、あなたのメールを使用して他の誰かが作成したアカウントを確認し、あなたになりすますことができるようになります。
CodesInChaos

@CodesInChaos-それはストレッチです。偽装は、同じメールアドレスではなく、同じユーザー名または公開の個人名から行われます。これは、使用するメールアドレスに関係なく発生する可能性があります(通常、サーバーのみがアカウント所有者のメールアドレスを知っています)。また、他の人のメールアドレスでアカウントを作成しても意味がありません。それは彼らをどのように助けることができますか?彼らは自分のアカウントを制御できませんでした。
TTT
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.