web-dev-qa-db-ja.com

PHPインクルードファイルへの直接アクセスを禁止する

インクルードとして排他的に使用するphpファイルがあります。したがって、URLを含める代わりにURLを入力して直接アクセスすると、エラーを実行する代わりにエラーをスローしたいと思います。

基本的には、phpファイルで次のようにチェックする必要があります。

if ( $REQUEST_URL == $URL_OF_CURRENT_PAGE ) die ("Direct access not premitted");

これを行う簡単な方法はありますか?

155
Alterlife

一般的な「Apacheサーバーで実行されているPHPアプリを完全に制御できる場合とできない場合」の状況の最も簡単な方法は、インクルードをディレクトリに配置し、.htaccessファイルでそのディレクトリへのアクセスを拒否することです。 Apacheを使用している場合、人々にグーグルの問題を防ぐために、アクセスしたくないディレクトリの「.htaccess」というファイルにこれを配置します。

Deny from all

実際にサーバーを完全に制御できる場合(この答えを最初に書いたときよりも小さなアプリでも最近ではより一般的です)、最善の方法は、保護するファイルをWebサーバーが提供しているディレクトリの外側に固定することです。したがって、アプリが/srv/YourApp/にある場合は、/srv/YourApp/app/からファイルを提供するようにサーバーを設定し、/srv/YourApp/includesにインクルードを配置します。したがって、文字通りそれらにアクセスできるURLはありません。

156
Chuck

含めるだけにするページにこれを追加します

<?php
if(!defined('MyConst')) {
   die('Direct access not permitted');
}
?>

それを含むページに追加します

<?php
define('MyConst', TRUE);
?>
172
UnkwnTech

ファイルが含まれているときと直接アクセスされているとき(主にprint()return())に異なる動作をする必要があるファイルがあります。変更されたコードを次に示します。

if(count(get_included_files()) ==1) exit("Direct access not permitted.");

アクセスされるファイルは常にインクルードファイルであるため、== 1です。

106
null

ファイルへの直接アクセスを防ぐ最善の方法は、ファイルをWebサーバーのドキュメントルートの外側(通常は1レベル上)に配置することです。それらを含めることはできますが、httpリクエストを介してアクセスする可能性はありません。

私は通常、すべてのPHPファイルをドキュメントルートの外に bootstrap file -ルーティングを開始するドキュメントルートの唯一のindex.phpを除いて配置します。ウェブサイト/アプリケーション全体。

31
Eran Galperin

Chuckのソリューションの代替(または補完)は、特定のパターンに一致するファイルへのアクセスを.htaccessファイルに入れて拒否することです。

<FilesMatch "\.(inc)$">
    Order deny,allow
    Deny from all
</FilesMatch>
25
Kevin Loney

1:含まれるファイルの数を確認する

if( count(get_included_files()) == ((version_compare(PHP_VERSION, '5.0.0', '>='))?1:0) )
{
    exit('Restricted Access');
}

Logic:PHPは、最小インクルードカウントが満たされない場合に終了します。 PHP5より前は、ベースページはインクルードと見なされないことに注意してください。


2:グローバル定数の定義と検証

// In the base page (directly accessed):
define('_DEFVAR', 1);

// In the include files (where direct access isn't permitted):
defined('_DEFVAR') or exit('Restricted Access');

Logic:定数が定義されていない場合、実行はベースページから開始されず、PHPは停止します実行中。


3:リモートアドレス認証

// Call the include from the base page(directly accessed):
$includeData = file_get_contents("http://127.0.0.1/component.php?auth=token");

// In the include files (where direct access isn't permitted):
$src = $_SERVER['REMOTE_ADDR']; // Get the source address
$auth = authoriseIP($src); // Authorisation algorithm
if( !$auth ) exit('Restricted Access');

このメソッドの欠点は、内部リクエストでセッショントークンが提供されない限り、実行が分離されることです。単一サーバー構成の場合はループバックアドレス、またはマルチサーバーまたは負荷分散サーバーインフラストラクチャのアドレスホワイトリストを使用して確認します。


4:トークン認証

前の方法と同様に、GETまたはPOSTを使用して、インクルードファイルに認証トークンを渡すことができます。

if($key!="serv97602"){header("Location: ".$Dart);exit();}

非常に厄介な方法ですが、適切な方法で使用すると、同時に最も安全で汎用性が高くなります。


5:Webサーバー固有の構成

ほとんどのサーバーでは、個々のファイルまたはディレクトリにアクセス許可を割り当てることができます。すべてのインクルードをこのような制限されたディレクトリに配置し、それらを拒否するようにサーバーを構成できます。

たとえば、Apacheでは、構成は.htaccessファイルに保存されます。チュートリアル ここ

ただし、サーバー固有の構成は推奨されませんそれらは異なるWebサーバー間での移植性が悪い。拒否アルゴリズムが複雑な場合、または拒否されたディレクトリのリストがかなり大きい場合、再構成セッションがかなり厄介になるだけです。最後に、コードでこれを処理するのが最善です。


6:インクルードをサイトルート外の安全なディレクトリに配置する

サーバー環境でのアクセス制限のために最も好ましくありませんが、ファイルシステムにアクセスできる場合はかなり強力な方法です。

//Your secure dir path based on server file-system
$secure_dir=dirname($_SERVER['DOCUMENT_ROOT']).DIRECTORY_SEPARATOR."secure".DIRECTORY_SEPARATOR;
include($secure_dir."securepage.php");

論理:

  • リンクはWebサイトのアドレスシステムの範囲外であるため、ユーザーはhtdocsフォルダー外のファイルを要求できません。
  • PHPサーバーはファイルシステムにネイティブにアクセスするため、必要な特権を持つ通常のプログラムができるように、コンピューター上のファイルにアクセスできます。
  • インクルードファイルをこのディレクトリに配置することにより、ユーザーに対してホットリンクが拒否されている間に、PHPサーバーがそれらにアクセスできるようにすることができます。
  • ウェブサーバーのファイルシステムアクセス設定が適切に行われなかったとしても、この方法はそれらのファイルが誤って公開されるのを防ぎます。

私の正統でないコーディング規約を許してください。フィードバックは大歓迎です。

24
RiA

実際、私のアドバイスは、これらのベストプラクティスをすべて実行することです。

  • ドキュメントをウェブルートORの外側に配置し、ウェブサーバーによるアクセスを拒否するディレクトリに
  • 非表示ドキュメントがチェックする可視ドキュメントで定義を使用します。
      if (!defined(INCL_FILE_FOO)) {
          header('HTTP/1.0 403 Forbidden');
          exit;
      }

このようにして、ファイルが何らかの方法で誤配置された場合(誤ったftp操作)、ファイルは保護されます。

15
jmucchiello

私は一度この問題を抱えていて、解決しました:

if (strpos($_SERVER['REQUEST_URI'], basename(__FILE__)) !== false) ...

しかし、理想的な解決策は、別のanwserで述べられているように、Webサーバーのドキュメントルートの外部にファイルを配置することです。

7
mati

1つの入り口でアプリケーションをビルドする方がよいでしょう。つまり、すべてのファイルはindex.phpから到達する必要があります。

これをindex.phpに配置します

define(A,true);

このチェックは、リンクされた各ファイルで実行する必要があります(requireまたはinclude経由)

defined('A') or die(header('HTTP/1.0 403 Forbidden'));
5
user2221806
debug_backtrace() || die ("Direct access not permitted");
4
Unirgy

PHPファイルへのアクセスを直接制限したかったのですが、jQuery $.ajax (XMLHttpRequest)経由で呼び出すこともできました。ここに私のために働いたものがあります。

if (empty($_SERVER["HTTP_X_REQUESTED_WITH"]) && $_SERVER["HTTP_X_REQUESTED_WITH"] != "XMLHttpRequest") {
    if (realpath($_SERVER["SCRIPT_FILENAME"]) == __FILE__) { // direct access denied
        header("Location: /403");
        exit;
    }
}
4
krasenslavov

何Joomla!ルートファイルで定数を定義し、インクルードファイルで同じものが定義されているかどうかを確認します。

defined('_JEXEC') or die('Restricted access');

または

codeIgniterのようなほとんどのフレームワークが推奨するように、webrootディレクトリの外部に配置することにより、すべてのファイルをhttpリクエストの範囲外に保つことができます。

または、インクルードフォルダー内に.htaccessファイルを配置してルールを記述することで、直接アクセスを防ぐことができます。

4
Pradeesh kumar

最も簡単な方法は、インクルードを呼び出すファイルに次のような変数を設定することです。

$including = true;

次に、含まれているファイルで、変数を確認します

if (!$including) exit("direct access not permitted");
4
Kyle Cronin

.htaccess以外にも、さまざまなフレームワーク、たとえばRuby on Railsで有用なパターンを見てきました。アプリケーションのルートディレクトリに個別のpub /ディレクトリがあり、ライブラリディレクトリは次のディレクトリにあります。 同じレベル pub /として。このようなもの(理想的ではありませんが、アイデアは得られます):

app/
 |
 +--pub/
 |
 +--lib/
 |
 +--conf/
 |
 +--models/
 |
 +--views/
 |
 +--controllers/

文書ルートとしてpub /を使用するようにWebサーバーをセットアップします。これにより、スクリプトの保護が強化されます。ドキュメントルートから必要なコンポーネントをロードするためにアクセスすることはできますが、インターネットからコンポーネントにアクセスすることはできません。セキュリティ以外のもう1つの利点は、すべてが1か所にあることです。

「アクセスが許可されていない」というメッセージは攻撃者の手がかりであり、ホワイトリストベースではないため、.htaccess設定よりも優れているため、このセットアップは、含まれるすべてのファイルにチェックを作成するよりも優れています。 lib /、conf /などのディレクトリには表示されません。

3
bandi

より正確な場合、この条件を使用する必要があります。

if (array_search(__FILE__, get_included_files()) === 0) {
    echo 'direct access';
}
else {
    echo 'included';
}

get_included_files() は、すべてのインクルードファイルの名前を含むインデックス付き配列を返します(ファイルが実行された場合、ファイルはインクルードされ、その名前は配列内にあります)。そのため、ファイルに直接アクセスすると、その名前が配列の最初になり、配列内の他のすべてのファイルが含まれます。

2
Oleg Lokshyn
if (basename($_SERVER['PHP_SELF']) == basename(__FILE__)) { die('Access denied'); };
1
andy
<?php
if (eregi("YOUR_INCLUDED_PHP_FILE_NAME", $_SERVER['PHP_SELF'])) { 
 die("<h4>You don't have right permission to access this file directly.</h4>");
}
?>

含まれているphpファイルの上部に上記のコードを配置します。

例:

<?php
if (eregi("some_functions.php", $_SERVER['PHP_SELF'])) {
    die("<h4>You don't have right permission to access this file directly.</h4>");
}

    // do something
?>
1
Blogging Tips

Flatnux CMSでは次のコードが使用されます( http://flatnux.altervista.org ):

if ( strpos(strtolower($_SERVER['SCRIPT_NAME']),strtolower(basename(__FILE__))) )
{
    header("Location: ../../index.php");
    die("...");
}
1
JohnRDOrazio

私の答えはアプローチが多少異なりますが、ここで提供される答えの多くが含まれています。多面的なアプローチをお勧めします。

  1. .htaccessおよびApacheの制限事項
  2. defined('_SOMECONSTANT') or die('Hackers! Be gone!');

ただしdefined or dieアプローチには多くの失敗があります。第一に、テストとデバッグの前提が本当に痛いです。第二に、それはあなたがあなたの心を変えた場合、恐ろしく、気が遠くなるほど退屈なリファクタリングを伴います。 「検索して交換!」あなたは言う。はい、しかし、どこでもまったく同じように書かれていると確信していますか?それを何千ものファイルで乗算します... o.O

そして、.htaccessがあります。管理者がそれほど綿密でないサイトにコードを配布するとどうなりますか?ファイルを保護するために.htaccessのみに依存している場合は、a)バックアップ、b)涙を乾かすためのティッシュの箱、c)人々からのすべてのヘイトメールの炎を消すための消火器も必要になりますコードを使用します。

だから私は質問が「最も簡単な」を求めていることを知っていますが、これが求めるのはより「防御的なコーディング」だと思います。

私が提案するのは:

  1. スクリプトの前にrequire('ifyoulieyougonnadie.php');notinclude()およびdefined or dieの代わりとして)
  2. ifyoulieyougonnadie.phpで、いくつかのロジックを実行します-異なる定数の確認、スクリプトの呼び出し、localhostテストなど-そして、die(), throw new Exception, 403などを実装します。

    メインのindex.php(Joomlaフレームワーク)とajaxrouter.php(私のフレームワーク)の2つの可能なエントリポイントを使用して独自のフレームワークを作成しているため、エントリポイントに応じて、さまざまなことを確認します。 ifyoulieyougonnadie.phpへのリクエストがこれらの2つのファイルのいずれかから来ていない場合、シェナンガンが行われていることがわかります!

    しかし、新しいエントリポイントを追加するとどうなりますか?心配ない。 ifyoulieyougonnadie.phpを変更するだけで、並べ替えられますが、「検索と置換」はありません。やった!

    同じ定数defined()を持たない別のフレームワークを実行するためにスクリプトの一部を移動することにした場合はどうなりますか? ...やれやれ! ^ _ ^

この戦略により、開発がより楽しくなり、より少なくなります。

/**
 * Hmmm... why is my netbeans debugger only showing a blank white page 
 * for this script (that is being tested outside the framework)?
 * Later... I just don't understand why my code is not working...
 * Much later... There are no error messages or anything! 
 * Why is it not working!?!
 * I HATE PHP!!!
 * 
 * Scroll back to the top of my 100s of lines of code...
 * U_U
 *
 * Sorry PHP. I didn't mean what I said. I was just upset.
 */

 // defined('_JEXEC') or die();

 class perfectlyWorkingCode {}

 perfectlyWorkingCode::nowDoingStuffBecauseIRememberedToCommentOutTheDie();
1
Just Plain High
if ( ! defined('BASEPATH')) exit('No direct script access allowed');

仕事をスムーズにします

0
Varshaan

PhpMyAdminスタイルを使用できます。

/**
 * block attempts to directly run this script
 */
if (getcwd() == dirname(__FILE__)) {
    die('Attack stopped');
}
0
namco
<?php       
$url = 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
  if (false !== strpos($url,'.php')) {
      die ("Direct access not premitted");
  }
?>
0
Matt Bettiol

これは、GoogleがPHPの例で使用するものです こちらを参照

if (php_sapi_name() != 'cli') {
  throw new \Exception('This application must be run on the command line.');
}
0
Toskan

インクルードファイルをWebでアクセス可能なディレクトリの外に保存することは何度か言及されており、可能な限り確かに良い戦略です。ただし、まだ言及していない別のオプション:インクルードファイルを確認してください実行可能なコードを含めないでください。インクルードファイルが関数とクラスを定義するだけで、それ以外のコードがない場合は、直接アクセスすると空白ページが生成されます。

ブラウザからこのファイルへの直接アクセスを許可します:it 何もしません。それはいくつかの関数を定義しますが、それらのどれも呼び出されないので、それらのどれも実行されません。

<?php

function a() {
    // function body
}

function b() {
    // function body
}

同じことがPHPクラスのみを含むファイルにも当てはまり、それ以外は何もありません。


可能な場合は、ファイルをウェブディレクトリ外に保管することをお勧めします。

  • 誤ってPHPを無効にする場合があります。この場合、サーバーはPHPを実行して結果を送信する代わりに、PHPファイルのコンテンツをブラウザーに送信します。これにより、コード(データベースパスワード、APIキーなどを含む)がリークする可能性があります。
  • Webディレクトリ内のファイルは、アプリに使用したいURLにしゃがみ込んでいます。 systemというページを使用できないCMSを使用しています。これは、コードに使用されるパスと競合するためです。これは迷惑です。
0
TRiG

また、できることは、ディレクトリをパスワードで保護し、そこにすべてのphpスクリプトを保持することです。もちろん、index.phpファイルを除きます。これは、httpアクセスにのみ必要となるため、インクルードパスワードは必要ありません。また、そのディレクトリにアクセスするためのパスワードがあるため、必要に応じてスクリプトにアクセスするオプションも提供します。ディレクトリの.htaccessファイルと、ユーザーを認証するための.htpasswdファイルをセットアップする必要があります。

また、cPanelなどを介していつでもアクセスできるため、通常これらのファイルにアクセスする必要がないと感じた場合は、上記のソリューションを使用することもできます。

お役に立てれば

0
RohitG

次のようなことをしてください:

<?php
if ($_SERVER['SCRIPT_FILENAME'] == '<path to php include file>') {
    header('HTTP/1.0 403 Forbidden');
    exit('Forbidden');
}
?>
0
kmkaplan

ユーザーがアクセスできるようにする可能性のあるフォルダ内の他のコンテンツをブロックする可能性があるため、.htaccessの提案はあまりよくありませんでした。これが私の解決策です。

$currentFileInfo = pathinfo(__FILE__);
$requestInfo = pathinfo($_SERVER['REQUEST_URI']);
if($currentFileInfo['basename'] == $requestInfo['basename']){
    // direct access to file
}
0
talsibony

セキュリティ上の理由から$_SERVERを使用しないことをお勧めします。
別のファイルを含む最初のファイルで$root=true;などの変数を使用できます。
そして含まれる2番目のファイルの先頭でisset($root)を使用します。

0
Mohamad Rostami

以下のメソッドを使用できますが、偽造される可能性があるため、別のコード行を追加して、JavaScriptを使用してサーバーからのみリクエストを送信できるようにする場合を除き、欠陥があります。このコードをHTMLコードのBodyセクションに配置すると、エラーが表示されます。

<?
if(!isset($_SERVER['HTTP_REQUEST'])) { include ('error_file.php'); }
else { ?>

他のHTMLコードをここに配置します

<? } ?>

このように終了すると、エラーの出力は常に本体セクション内に表示されます(必要に応じて)。

0
Charming Prince

Httpとcliの両方で動作するこのphpのみで不変のソリューションを見つけました。

関数を定義する:

function forbidDirectAccess($file) {
    $self = getcwd()."/".trim($_SERVER["PHP_SELF"], "/");
    (substr_compare($file, $self, -strlen($self)) != 0) or die('Restricted access');
}

に直接アクセスしたくないファイルの関数を呼び出します:

forbidDirectAccess(__FILE__);

この質問に対する上記のソリューションのほとんどは、Cliモードでは機能しません。

0
Ka.

最も簡単な方法は、インクルードをWebディレクトリの外部に保存することです。そうすれば、サーバーはそれらにアクセスできますが、外部のマシンにはアクセスできません。唯一の欠点は、サーバーのこの部分にアクセスできる必要があることです。利点は、セットアップ、構成、または追加のコード/サーバーストレスを必要としないことです。

0
user1391838