ホルモンholywar管理者および開発者PHPまたはREMOTE_ADDR vs HTTP_X_FORWARDED_FOR

最近、彼はPHPスクリプトからエンドユーザーのIPアドレスを決定することが本当に必要であるかについての興味深い議論を目撃しました。

実際、主題の各単語は実際の状況を反映しています。 それは宗教的な議論であり、素晴らしい春の天候によって悪化しました。そこでは、善悪はありませんでしたが、少しの研究を促し、私の幸福に、この告白の理解を終わらせましたが、実際には非常に簡単な質問でした。

私のように、私はそれを理解したと確信している人のために、ささいなことを理解するのが面倒すぎることを恐れました -猫の下で。





背景



Samsung SmartTVプラットフォーム用のVODサービスを開発する場合、著作権所有者が禁止している映画を誤って幸せなユーザーに見せないように、ユーザーの国を確実に知る必要があります。しかし、この契約期間の違反は、数千ドルの子供の罰金を伴いません見落とし)。

[コメントで指摘されているように、質問は合法であり、詐欺は可能ですが、記事はそのような詐欺を防ぐ方法についてではなく、phpとnginxを正しく友達にする方法についてです]



サーバーには次のものがあります:php-fpm + nginx



国を決定する方法は? まあ、当然、ユーザーのIPおよびGEO IPベースmaxmindを通じて

「... そして、彼のバイクを書かないために、彼はstackoverflowグーグルで検索し 、すべての行を詳しく調べ 、それをねじ込んでそこに残して、コードが成長しました:



public function getUserHostAddress(){ if (!empty($_SERVER['HTTP_X_REAL_IP'])) //check ip from share internet { $ip=$_SERVER['HTTP_X_REAL_IP']; } elseif (!empty($_SERVER['HTTP_CLIENT_IP'])) //check ip from share internet { $ip=$_SERVER['HTTP_CLIENT_IP']; } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) //to check ip is pass from proxy { $ip=$_SERVER['HTTP_X_FORWARDED_FOR']; } else { $ip=$_SERVER['REMOTE_ADDR']; } return $ip; }
      
      







そしてうまくいきました! ほぼ1年...予期せぬことが起こるまで。 このコードでは当然のことながら...



PHPまたはプロキシチェーンを混乱させる方法(歴史の一部)



すべてが壊れています! そして、これは、支払いシステムの1つを台無しにしなければならず、1つのアドレスがHTTP_X_FORWARDED_FORではなく、コンマで区切られたアドレスのリスト(厳密に言えば、合法で許容され、 PHPドックで規制されていないため)すべてのコードがクラッシュしたときに起こりました

また、HTTP_X_REAL_IPまたはHTTP_CLIENT_IP(これもドックによって規制されていない)に目的のIPが含まれていたとしても、誰も気付かなかったでしょうが、残念ながらそれらは空でした:(



「さて」と思いました(今はもう一人ではありません)、すべてを書き直して、管理者にユーザーIPをREMOTE_ADDR変数にプッシュするように依頼します。



  public function getUserHostAddress(){ $ip=$_SERVER['REMOTE_ADDR']; return $ip; }
      
      







そしてうまくいきました! ほぼ1か月...予期しないことが発生するまで。 このコードでは当然のことながら...



タフな男性の春の議論(これは皮肉ではありません-彼らはクールです)



すべてが壊れています! これは、nginxを更新する必要があるために発生しました。 そして、この問題の専門家、つまり管理者に頼りました。

そして、それらは、構成を更新し、REMOTE_ADDRに転送して「松葉杖/松葉杖ではない」(これを理解するまで)を取り除くことにしました。



REMOTE_ADDRは変更されずに残っています。 現在、「127.0.0.1」のようなものが輝いていました

HTTP_X_FORWARDED_FORでは、ユーザーのIPが詐欺されました(それまでは、ブラウザーからヘッダー `x-forwarded-for:999.999.999.999`を送信することで簡単に上書きされました)

そして、それが始まりました-P =開発、A =管理者:



A:すべてが故障しました。nginxプロキシがあるため、必要なアドレスはHTTP_X_FORWARDED_FORにあり、REMOTE_ADDRにはphp-fpmへのクライアントの実際のIPアドレスがあります(つまり127.0.0.1)

R:しかし、HTTP_X_FORWARDED_FORは信じられません。これは、ヘッダーを介してサーバーに簡単に再定義できる変数であり、かなり興味深い記事を引用して

A:いいえ、エンドユーザーの実際のIPを含め、REMOTE_ADDRにはphpへの実際のクライアントアドレスを含めます

R:その後、プロキシのシーケンスに従いませんが、別のサーバーでの普遍化(プロキシなしなど)のために、これらの構成はREMOTE_ADDRのすべてを突き詰めるとは限りません。



...それは簡単でマットなしです...



その結果、当然、すべてが起動し、必要な状態でプロキシとすべての変数(より正確には注意を払う必要のある変数)なしでクライアントが直接接続されているとphpが判断したときに、透過プロキシに落ち着きました。

ただし、この問題には風水が十分ではなく、実際にはプロキシがあり、 プロキシはありません。



誰が責任があるのか​​、誰が正しいのか



私たちが判断するのではなく、誰も判断しません!



本当にPHPに直接クライアントの束、または透過的なプロキシがある場合、すべては簡単です-健康のためにREMOTE_ADDRを使用してお楽しみください。



しかし、通常のプロキシを使用し、PHPにそれを知らせたい場合、ファニングについてはどうでしょうか。



レシピ...しかし万能薬ではない:





結論として



php + nginxにはいくつかのプロキシオプションがあります





PS

後で風水を設定に入れて透過的なプロキシを削除し、両方のプロキシの場合にIPを決定する汎用関数を作成します。



PPS

楽しみのために、誰が気にします:コメントの誰かがこの関数を書いて、nginx configが私たちのためにあり、それを使用するなら、正直に、彼は電話に100ルーブルを受け取ります。

しかし、この関数と設定は本当に正統であり、すべてを考慮する必要があります:)すべての手がかりは記事にあります。

主なものはZenです。時間をかけてください-突然、最初のものがエラーで書き込まれ、それらを考慮して、急いでください-突然、最初の正しい答えはあなた次第です。



どうもありがとう。 良い春を! 同僚とアレンジして、彼らを愛してください! :)



UDP:

独自の実装:

  /** * @param null|string $ip_param_name -   _SERVER,     IP  *       REMOTE_ADDR       , *     IP    , *    HTTP_X_REAL_IP    * @param bool $allow_non_trusted - ,   $ip_param_name  *      _SERVER[$ip_param_name] *      _SERVER     $non_trusted_param_names * @param array $non_trusted_param_names -  ,     IP   _SERVER * @throws Exception * @return string */ public function getUserHostAddress( $ip_param_name = null, $allow_non_trusted = false, array $non_trusted_param_names = array('HTTP_X_REAL_IP','HTTP_CLIENT_IP','HTTP_X_FORWARDED_FOR','REMOTE_ADDR') ){ if(empty($ip_param_name) || !is_string($ip_param_name)){ //       $ip = $_SERVER['REMOTE_ADDR']; }else{ //    if(!empty($_SERVER[$ip_param_name]) && filter_var($_SERVER[$ip_param_name], FILTER_VALIDATE_IP)){ //      $ip = $_SERVER[$ip_param_name]; }else if($allow_non_trusted){ //           foreach($non_trusted_param_names as $ip_param_name_nt){ if($ip_param_name === $ip_param_name_nt) //      continue; if(!empty($_SERVER[$ip_param_name_nt]) && filter_var($_SERVER[$ip_param_name_nt], FILTER_VALIDATE_IP)){ //      $ip = $_SERVER[$ip_param_name_nt]; break; } } } } if(empty($ip)) //      ip,     $_SERVER['REMOTE_ADDR'] -   throw new Exception("Can't detect IP"); return $ip; }
      
      






All Articles