2

私の webapp にはたくさんのモジュールがあります。各モジュールには、メイン モジュールに送信されたクエリに基づいてサブモジュールをロードする「メイン」php スクリプトがあります。

//file: clientes.php

//check for valid user...
//import CSS and JS...

switch( $_GET["action"] )
{
    case "lista" :          require_once("clientes.lista.php"); break;
    case "listaDeudores" :  require_once("clientes.listaDeudores.php"); break;
    case "nuevo" :          require_once("clientes.nuevo.php"); break;
    case "detalles" :       require_once("clientes.detalles.php"); break;
    case "editar" :         require_once("clientes.editar.php"); break;         
    default : echo "<h1>Error</h1><p>El sitio ha encontrado un error.</p>";
} 

このメイン モジュールはセキュリティを処理し、すべてのサブモジュールが必要とする多くのリソースをインポートします。ユーザーがメインモジュールのすべてのセキュリティ対策をバイパスして、サブモジュールのいずれかを要求すると、大きな問題が発生します! 私の考えは、すべてのサブモジュールに行を追加して、直接呼び出されてアクセスを拒否するか、別のスクリプトを介して呼び出されたかをテストして続行することでした。データベースに対して一連のクエリを実行するため、すべてのファイルのセキュリティ チェックをやり直すことは、私が最もやりたいことではありません。

PHPスクリプトは、require_once()それが直接呼び出しまたは直接呼び出しによって呼び出されたかどうかを知っていますか? 私はある種の落とし穴を実装しようとしてきましたが$_SERVER['REQUEST_URI']$_SERVER['PHP_SELF']これを行うエレガントな方法があるかどうか疑問に思っていました。

4

11 に答える 11

21

ファイルが含まれているか、ファイル内から直接呼び出されているかを判断する方法を探していました。私の探求のある時点で、私はこのスレッドを通過しました。PHP マニュアルのこのサイトや他のサイトやページの他のさまざまなスレッドをチェックして、悟りを得て、次のコードを思いつきました。

if ( basename(__FILE__) == basename($_SERVER["SCRIPT_FILENAME"]) ) {
  echo "called directly";
}

else {
  echo "included/required"
}

本質的には、現在のファイル (含めることができるファイル) の名前が実行中のファイルと同じかどうかを比較します。


説明:

  • __FILE__ は、ファイルのフル パスとファイル名を格納する PHP マジック定数です。その優れた点は、ファイルがインクルードまたは要求されている場合でも、そのようなファイル (インクルード ファイル) のフル パスとファイル名を返すことです。
    (マジック定数マニュアル: http://php.net/manual/en/language.constants.predefined.php )

  • $_SERVER["SCRIPT_FILENAME"] は、現在実行中のスクリプトの絶対パス名を返します。ファイルが含まれている/要求されている場合、実行されていない (単に含まれている) ため、(たとえば)「親」ファイル (他のファイルを含むファイルと実行されるファイル) のパス名を返します。

  • basename(string $path) は、パスの末尾の名前コンポーネント (この場合はファイル名) を返す関数です。フル パスとファイル名を比較することもできます。その方が実際に優れています。この関数を使用する必要はありませんが、この方法の方がすっきりと感じられます、jajaj。
    (basename(): http://php.net/manual/en/function.basename.php )

主な質問に答えるのが「少し」遅れていることはわかっていますが、私と同じ状況にあり、通りかかった人にとっては役立つと思いました。

于 2011-08-29T02:55:51.780 に答える
13

洗練された方法の 1 つは、include を介してのみアクセスできるすべてのファイルをweb ディレクトリの外に置くことです。

Web ディレクトリが /foo/www/ であるとすると、インクルード ディレクトリ /foo/includes を作成し、これを include_path に設定します。

$root = '/foo';
$webroot = $root.'/www'; // in case you need it on day
$lib = $root.'/includes';
// this add your library at the end of the current include_path
set_include_path(get_include_path() . PATH_SEPARATOR . $lib); 

その後、誰もあなたのライブラリに直接アクセスできなくなります。

他にもできることはたくさんあります (グローバル変数が設定されていることをテストする、ライブラリ内のクラスのみを使用するなど) が、これが最も安全なものです。DocumentRoot にないすべてのファイルには、URL 経由でアクセスできません。しかし、それは PHP がこのファイルにアクセスできないという意味ではありません (空でない場合は、open_basedir の設定も確認して、そこにディレクトリを含めることができるようにしてください)。

Web ディレクトリに本当に必要な唯一のファイルは、ブートストラップ (index.php) と呼ばれるものです。適切な書き換えルールまたは適切な URL 管理を使用すると、アプリケーションのすべての要求をこのファイルに制限できます。セキュリティの出発点。

于 2010-12-28T12:14:31.137 に答える
6

モジュールが直接呼び出されないようにする一般的な方法の 1 つは、メイン スクリプトで定数を定義し、モジュールでその定数をチェックすることです。

// index.php
define("LEGIT_REQUEST", true);

// in each module
if (!defined("LEGIT_REQUEST")) 
  die ("This module cannot be called directly.");
于 2010-12-28T12:07:15.317 に答える
5

完全を期すために、他の可能性は、そのようなファイルを公開されていないディレクトリに移動することです。ただし、ホスティング プロバイダーが使用する一部のコントロール パネルでは、これが不可能になります。このような場合、Apache を使用している場合は.htaccess、ディレクトリ内にファイルを配置できます。

#
# Private directory
#
Order allow,deny
Deny from all
于 2010-12-28T12:17:09.527 に答える
4

一般的な手法は、これをメイン モジュールに追加することです (インクルードの前)。

define('TEST', true);

そして、すべてのサブモジュールの最初の行にそのようなものを追加します

if (!defined('TEST')) {
    die('Do not cheat.');
}
于 2010-12-28T12:09:54.830 に答える
3

定数を定義してチェックする代わりに、 index.php に含まれるファイルをドキュメントのルート領域の外に置くだけです。そうすれば、ユーザーは Web サーバー経由でそれらに直接アクセスできなくなります。これは明らかに最も安全な方法でもあります。これは、将来、Web サーバーに構成エラーが発生した場合に備えて、. PHP ファイルをプレーンテキストとして表示します。

于 2010-12-28T12:15:09.043 に答える
1

グローバル.php

if(!defined("in_myscript"))
{
    die("Direct access forbidden.");
}

モジュール.php

define("in_myscript", 1);
include("global.php");
于 2010-12-28T12:10:37.190 に答える
1

定数を定義したり、htaccess を使用したり、特定のディレクトリ構造を使用したり、理論的に変更できる $_SERVER 配列に依存したりする必要なく機能する一般的な方法は、次のコードで各インクルードのみ (直接アクセスなし) ファイルを開始することです。

<?php $inc = get_included_files(); if(basename(__FILE__) == basename($inc[0])) exit();
于 2014-03-22T08:01:15.637 に答える
1

define('SOMETHING', null)clientes.php でif (!defined('SOMETHING')) die;モジュールをチェックインできます。

于 2010-12-28T12:09:42.910 に答える
0

習慣として、メッセージやエラーなどを FirePHP でコンソールに送信するコンソール クラスを作成しました。Console クラスの write() メソッド内で、$_REQUEST[debug] == 1 かどうかを確認するためのチェックがあります。これにより、本番環境で何かがポップアップした場合にユーザーにエラーを公開せず、ユーザーは要求が何であるかを知る必要があります。 variable は、デバッグ情報にアクセスするためのものです。

追加するすべてのファイルの上部に:

Console::debug('fileName.php is loaded.');

ここに正しいアイデアを提供するためのスニピットがあります:

class Console{

  public static function write($msg,$msg_type='info',$msg_label=''){
    if(isset($_REQUEST['debug']) && $_REQUEST['debug'] == 'PANCAKE!'){
      ob_start();
      switch($msg_type){
        case 'info':
          FB::info($msg, $msg_label);
          break;
        case 'debug':
          FB::info($msg, 'DEBUG')
          break;
          ...
      }
    }
  }

  public static function debug($msg){
    Console::write($msg, '');
  }
}
于 2010-12-28T15:04:27.890 に答える