web-dev-qa-db-ja.com

$ _SERVER []はPHPの安全なデータソースですか?

100%信頼できますか$_SERVER[]私が行うようにサニタイズする必要のない安全なデータソースになる$_GET[]および$_POST[]

29
user2079272

これは、スタックオーバーフローに関する私の質問の1つから取られたものです どの$ _SERVER変数が安全ですか?

サーバー制御

これらの変数はサーバー環境によって設定され、サーバー構成に完全に依存します。

  • 'GATEWAY_INTERFACE'
  • 'SERVER_ADDR'
  • 'SERVER_SOFTWARE'
  • 'DOCUMENT_ROOT'
  • 'SERVER_ADMIN'
  • 'SERVER_SIGNATURE'

部分的にサーバー制御

これらの変数は、クライアントが送信した特定のリクエストに依存しますが、すべての無効な値はWebサーバーによって拒否され、スクリプトの呼び出しを開始しないため、限られた数の有効な値しか取ることができません。したがって、それらはreliableと見なすことができます。

  • 'HTTPS'
  • 'REQUEST_TIME'
  • 'REMOTE_ADDR' *
  • 'REMOTE_Host' *
  • 'REMOTE_PORT' *
  • 'SERVER_PROTOCOL'
  • 'HTTP_Host'
  • 'SERVER_NAME'
  • 'SCRIPT_FILENAME'
  • 'SERVER_PORT'
  • 'SCRIPT_NAME'

* REMOTE_値は、TCP/IPハンドシェイクによって検証されるように、クライアントの有効なアドレスであることが保証されています。これは、応答が送信されるアドレスです。 REMOTE_Hostただし、逆DNSルックアップに依存しているため、サーバーに対するDNS攻撃によってスプーフィングされる可能性があります(この場合、とにかく大きな問題が発生します)。この値はプロキシである場合があります。これは、TCP/IPプロトコルの単純な現実であり、何も実行できません。

†WebサーバーがHostヘッダーに関係なくany要求に応答する場合、これも安全ではないと見なされます。 $ _ SERVER [“ HTTP_Host”]?は安全ですか? を参照してください。
http://shiflett.org/blog/2006/mar/server-name-versus-http-Host も参照してください。

完全に任意のユーザー制御値

これらの値はまったくチェックされず、サーバー構成に依存しません。これらは、クライアントから送信される完全に任意の情報です。

  • 'argv''argc'(CLI呼び出しにのみ適用可能で、通常はWebサーバーには関係ありません)
  • 'REQUEST_METHOD'
  • 'QUERY_STRING'
  • 'HTTP_ACCEPT'
  • 'HTTP_ACCEPT_CHARSET'
  • 'HTTP_ACCEPT_ENCODING'
  • 'HTTP_ACCEPT_LANGUAGE'
  • 'HTTP_CONNECTION'
  • 'HTTP_REFERER'
  • 'HTTP_USER_AGENT'
  • 'AUTH_TYPE'§
  • 'PHP_AUTH_DIGEST'§
  • 'PHP_AUTH_USER'§
  • 'PHP_AUTH_PW'§
  • 'PATH_INFO'
  • 'ORIG_PATH_INFO'
  • 'REQUEST_URI'(汚染されたデータが含まれている可能性があります)
  • 'PHP_SELF'(汚染されたデータ、つまり/index.php/evilstringが含まれている可能性があります)
  • 'PATH_TRANSLATED'
  • 他の 'HTTP_'

the Webサーバーが特定の要求メソッドのみを許可している限り、信頼できると見なされます。

§認証がWebサーバーによって完全に処理される場合、reliableと見なされます。

スーパーグローバル$_SERVERには、いくつかの環境変数も含まれています。これらが「安全」であるかどうかは、それらの定義方法(および場所)に依存します。完全にサーバー制御から完全にユーザー制御までさまざまです。

44
rook

$ _GET []や$ _POST []のようにサニタイズする必要のない安全なデータソースとして、$ _ SERVER []を100%信頼できますか?

あなたの質問はすぐに失敗を示します。入力のすべてのソースはサニタイズする必要があります。入力は、ユーザーが直接制御できるチャネルと見なされるだけでなく、アプリケーションの外部にあるすべてのデータソースと見なされます。

このように考えると、アプリケーションにはデータを取得する2つの方法があります。アプリケーションでハードコードされた情報と入力です。同じシステム上の別のプログラムによって生成されたとしても、それはあなたのプログラムへの入力のままです。

一般的なイディオム_Filter-In, Escape-Out_は、ユーザー入力だけでなく、アプリケーションに出入りするあらゆるものに適用されます。

したがって、それが_$_SERVER_内にある場合、それは[〜#〜] must [〜#〜]フィルタリング/サニタイズされる必要があります。アプリケーションでハードコーディングされていないものに依存することはできません。

何でこれが大切ですか?ユーザーからのすべての入力をフィルタリングし、データベースからのデータを信頼するとします。フィルタリングの穴を利用できれば、信頼できるデータを注入できます。これにより、2次のXSSまたはSQLiが発生する可能性があります。しかし、アプリケーションに含まれるすべてのものをフィルタリングすると、アプリケーションがどこから来た場合でも、どこから来ても安全です。

つまり、_$_SERVER_、_$_GET_、_$_POST_、_$_COOKIE_、_$_REQUEST_、_$_ENV_、_$argc_、_$argv_、データベース、ファイルシステム(バージョン管理コードを除く)などから...

14
ircmaxell

まったくばかげた質問ではありません!

$ SERVER変数の多く(すべてではない)がユーザーのブラウザーから渡されます(またはユーザーの影響を受ける可能性があります)。たとえば、QUERY_STRING、REQUEST_URI、およびすべてのHTTP_ *変数です。

REMOTE_ADDR変数でさえ、生のソケットを使用してスプーフィングされる可能性があります(ただし、私が知る限り、有効なIPを使用している場合のみです)。

私は良い政策の問題としてそれらすべてを逃れるでしょう。

http://php.net/manual/en/reserved.variables.server.php

6
GBC

「データの安全なソース」などはありません。他のデータに渡すときは、データが正しい形式であることを常に確認する必要があります。

アポストロフィ( ')で区切られた文字列[1]内でSQLに出力する場合は、アポストロフィ(または文字列を区切る可能性のあるその他の文字)をエスケープする必要があります。 Javascriptアポストロフィで区切られたstring [2]に出力する場合は、HTMLとアポストロフィの両方をエスケープする必要があります。それはすべて、出力先に依存します。完全に安全な文字列は、悪意のある方法でなくても、ターゲットスクリプトを破壊する可能性があります。 (ただし、壊れる可能性がある場合は、悪用されることもあります。)

[1]例:$db->query("SELECT * FROM users WHERE name = '$username'");
[2]例:<script>alert('Hi <?php echo $username;?>');</script>

私のブログでこのエスケープについて話しましたが、私の投稿は特にXSSについてですが、同じ原則がここでも当てはまると思います: XSSとは何ですか、またWebサイトを保護する方法

PHP自体が既に特定の形式を強制していることを知らない限り、ほとんど確実ではないので、すべてを安全でないと見なすことができます。IPアドレスは通常xxxx形式で提供されますが、 IPv6の場合はx:x:x:x:x:x:x:xです。IPv6パケットのIPv4宛先の場合は0:0:0:0:0:ffff:xxxxです。これに気付いていない場合は、それはいくつかの非常に興味深いバグにつながるかもしれません。

これで、IPアドレスにアポストロフィが含まれることはありません。リモートアドレスを使用する前に$ _SERVER ["HTTP_X_FORWARDED_FOR"]ヘッダーをチェックする人がいます。ヘッダーが正しく設定されている限り(@GBCの応答へのコメントで@Ladadadadaが指摘しているように)、これはすばらしいことですが、それもまたなりすましの可能性があります。次に、他の人がデータベースに保存したデータを使用すると、悪意のあるものを取り戻す可能性があります...つまり、結局、決して入力を信頼しないでください。一度忘れるよりも安全にしておく方がいいです。

3
Luc