インクルードとして排他的に使用するphpファイルがあります。したがって、含まれているのではなく、URLを入力して直接アクセスした場合、実行する代わりにエラーをスローしたいと思います。
基本的に、phpファイルで次のようにチェックを行う必要があります。
if ( $REQUEST_URL == $URL_OF_CURRENT_PAGE ) die ("Direct access not premitted");
これを行う簡単な方法はありますか?
インクルードとして排他的に使用するphpファイルがあります。したがって、含まれているのではなく、URLを入力して直接アクセスした場合、実行する代わりにエラーをスローしたいと思います。
基本的に、phpファイルで次のようにチェックを行う必要があります。
if ( $REQUEST_URL == $URL_OF_CURRENT_PAGE ) die ("Direct access not premitted");
これを行う簡単な方法はありますか?
回答:
一般的な「完全に制御できるかどうかにかかわらず、Apacheサーバー上で実行されているPHPアプリ」の最も簡単な方法は、インクルードをディレクトリに入れ、.htaccessファイルでそのディレクトリへのアクセスを拒否することです。人々がグーグルの手間を省くために、Apacheを使用している場合は、アクセスできないようにしたいディレクトリの「.htaccess」というファイルにこれを配置します。
Deny from all
実際にサーバーを完全に制御している場合(最近では、この答えを最初に書いたときよりも小さなアプリでも一般的です)、最善の方法は、Webサーバーがサービスを提供しているディレクトリの外側に保護するファイルを貼り付けることです。そのため、アプリがにある場合は、/srv/YourApp/
ファイルを提供するようにサーバーを設定し、インクルードを/srv/YourApp/app/
に配置して、/srv/YourApp/includes
文字通り、それらにアクセスできるURLがないようにします。
<Files ~ "\.inc$">
Order Allow,Deny
Deny from All
</Files>
これだけを含めたいページに追加します
<?php
if(!defined('MyConst')) {
die('Direct access not permitted');
}
?>
それを含むページに追加します
<?php
define('MyConst', TRUE);
?>
somefile.php
があなたのサーバーで作成し、それにあなたの定義を追加した場合、それでも彼らはインクルードファイルに直接アクセスできません。ライブラリファイルを「含める」ことができますが、サーバーでファイルを作成し、定義/含めるスクリプトを理解するのに十分な場合は、他の問題があり、そもそも定義を使用して独自のファイルを書き込むことができません。 。
ファイルが含まれている場合と直接アクセスされている場合(主にprint()
vs return()
)で異なる動作をする必要があるファイルがあります。変更されたコードを次に示します。
if(count(get_included_files()) ==1) exit("Direct access not permitted.");
アクセスされるファイルは常にインクルードファイルであるため、== 1です。
ファイルへの直接アクセスを防ぐ最良の方法は、ファイルをWebサーバーのドキュメントルートの外(通常は1レベル上)に置くことです。それらを含めることはできますが、誰かがhttpリクエストを通じてそれらにアクセスする可能性はありません。
私は通常、すべての方法で、ブートストラップファイルを除いて、すべてのPHPファイルをドキュメントルートの外側に配置します。ドキュメントルートにある単独のindex.phpは、Webサイト/アプリケーション全体のルーティングを開始します。
if( count(get_included_files()) == ((version_compare(PHP_VERSION, '5.0.0', '>='))?1:0) )
{
exit('Restricted Access');
}
ロジック:最小インクルード数が満たされない場合、PHPは終了します。PHP5より前のバージョンでは、ベースページはインクルードとは見なされません。
// 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');
ロジック:定数が定義されていない場合、実行はベースページから開始されず、PHPは実行を停止します。
注変更は、すべて単一のファイルにハードコーディングされたする必要がないので、アップグレードや将来の変化間の移植のために、この認証方法のモジュラーを作ることはかなりのオーバーヘッドのコーディングを減らすだろうと。
// Put the code in a separate file instead, say 'checkdefined.php':
defined('_DEFVAR') or exit('Restricted Access');
// Replace the same code in the include files with:
require_once('checkdefined.php');
このようにして、追加のコードをに追加して checkdefined.php
、ロギングと分析の目的で、適切な応答を生成できます。
クレジットの期限が到来するクレジット:移植性の素晴らしいアイデアは、この回答から生まれました。
// 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');
このメソッドの欠点は、内部リクエストでセッショントークンが提供されない限り、実行が分離されることです。単一サーバー構成の場合はループバックアドレス、マルチサーバーまたは負荷分散サーバーインフラストラクチャの場合はアドレスホワイトリストを使用して確認します。
前の方法と同様に、GETまたはPOSTを使用して、許可トークンをインクルードファイルに渡すことができます。
if($key!="serv97602"){header("Location: ".$dart);exit();}
非常に厄介な方法ですが、正しい方法で使用すると、おそらく最も安全で多用途な方法でもあります。
ほとんどのサーバーでは、個々のファイルまたはディレクトリに権限を割り当てることができます。すべてのインクルードをそのような制限されたディレクトリに配置し、それらを拒否するようにサーバーを構成することができます。
たとえばAPACHEでは、設定は.htaccess
ファイルに保存されます。チュートリアルはこちら。
注しかし、彼らは別のウェブサーバー間での移植のために悪いため、サーバー固有の構成は私が推奨されていないこと。コンテンツ管理システムのように、拒否アルゴリズムが複雑である場合、または拒否されたディレクトリのリストがかなり大きい場合、再構成セッションが煩雑になるだけです。結局、コードでこれを処理するのが最善です。
サーバー環境でのアクセス制限のため、あまり推奨されませんが、ファイルシステムにアクセスできる場合はかなり強力な方法です。
//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");
論理:
htdocs
リンクはWebサイトのアドレスシステムの範囲外であるため、ユーザーはフォルダーの外部にあるファイルを要求できません。私の正統でないコーディング規約を許してください。どんなフィードバックでもありがたいです。
実際、私のアドバイスは、これらすべてのベストプラクティスを実行することです。
if (!defined(INCL_FILE_FOO)) {
header('HTTP/1.0 403 Forbidden');
exit;
}
これにより、ファイルが何らかの理由で誤った場所に置かれた場合(誤ったFTP操作)、ファイルは引き続き保護されます。
あなたは1つの入り口でアプリケーションを構築するほうがいいです、すなわちすべてのファイルはindex.phpから到達されるべきです
これをindex.phpに配置します
define(A,true);
このチェックは、リンクされた各ファイルで実行する必要があります(requireまたはincludeを介して)
defined('A') or die(header('HTTP/1.0 403 Forbidden'));
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;
}
}
最も簡単な方法は、includeを呼び出す変数をファイルに設定することです。
$including = true;
次に、含まれているファイルで、変数を確認します
if (!$including) exit("direct access not permitted");
.htaccessの方法以外にも、Ruby on Railsなど、さまざまなフレームワークで有用なパターンを見てきました。それらはアプリケーションのルートディレクトリに別個のpub /ディレクトリを持ち、ライブラリディレクトリはpub / と同じレベルのディレクトリにあります。このようなもの(理想的ではありませんが、あなたはアイデアを得ます):
app/
|
+--pub/
|
+--lib/
|
+--conf/
|
+--models/
|
+--views/
|
+--controllers/
ドキュメントルートとしてpub /を使用するようにWebサーバーを設定します。これにより、スクリプトの保護が強化されます。ドキュメントルートから必要なコンポーネントをロードするためにアクセスすることはできますが、インターネットからコンポーネントにアクセスすることはできません。セキュリティ以外の利点は、すべてが1か所にあることです。
この設定は、「アクセスが許可されていません」というメッセージが攻撃者への手掛かりであるため、含まれているすべてのファイルにチェックを作成するだけではなく、ホワイトリストに基づいていないため、.htaccess構成よりも優れています。 lib /、conf /などのディレクトリには表示されません。
なんとJoomla!ルートファイルで定数を定義し、インクルードファイルで定数が定義されているかどうかを確認します。
defined('_JEXEC') or die('Restricted access');
さもなければ
CodeIgniterのようなほとんどのフレームワークが推奨するように、すべてのファイルをwebrootディレクトリの外に置くことで、すべてのファイルをhttpリクエストの範囲外に保つことができます。
または、インクルードフォルダー内に.htaccessファイルを配置してルールを記述することで、直接アクセスを防ぐことができます。
私の答えはアプローチが多少異なりますが、ここで提供される多くの答えが含まれています。私は多面的なアプローチをお勧めします:
defined('_SOMECONSTANT') or die('Hackers! Be gone!');
ただし、このdefined or die
アプローチには多くの欠点があります。第一に、テストとデバッグに使用する仮定の本当の痛みです。第二に、それはあなたがあなたの心を変えるならば、恐ろしいほど、心が何となく退屈なリファクタリングを含みます。「検索して置き換える!」あなたは言う。はい、でも、どこでもまったく同じように書かれていることをどれだけ確信していますか。それを数千のファイルで乗算します... oO
そして、.htaccessがあります。管理者がそれほど慎重ではないサイトにコードを配布するとどうなりますか?ファイルの保護に.htaccessのみに依存している場合は、a)バックアップ、b)涙を乾かすためのティッシュボックス、c)人からのすべてのヘイトメールで炎を消すための消火器あなたのコードを使用して。
だから私は質問が「最も簡単」を求めていることを知っていますが、これが要求するものはより「防御的なコーディング」だと思います。
私が提案するのは:
require('ifyoulieyougonnadie.php');
(ではなく include()
、の代わりとしてdefined or die
)ではifyoulieyougonnadie.php
、いくつかのロジックを実行します-さまざまな定数、呼び出しスクリプト、localhostテストなどを確認してからdie(), throw new Exception, 403
、を実装します。
2つの可能なエントリポイント(メインのindex.php(Joomlaフレームワーク)とajaxrouter.php(私のフレームワーク))を使用して独自のフレームワークを作成しています。へのリクエスト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();
より正確には、次の条件を使用する必要があります。
if (array_search(__FILE__, get_included_files()) === 0) {
echo 'direct access';
}
else {
echo 'included';
}
get_included_files()は、インクルードされたすべてのファイルの名前を含むインデックス付き配列を返します(ファイルが正常に実行されている場合、インクルードされ、その名前は配列にあります)。したがって、ファイルに直接アクセスすると、その名前が配列の最初になり、配列内の他のすべてのファイルが含まれます。
<?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
?>
次のコードは、Flatnux CMS(http://flatnux.altervista.org)で使用されています。
if ( strpos(strtolower($_SERVER['SCRIPT_NAME']),strtolower(basename(__FILE__))) )
{
header("Location: ../../index.php");
die("...");
}
私は、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モードでは機能しません。
インクルードファイルをWebのアクセス可能なディレクトリの外に保存することは何度か言及されており、可能な場合は確かに優れた戦略です。ただし、まだ言及していない別のオプションについては、インクルードファイルに実行可能なコードが含まれていないことを確認してください。インクルードファイルが関数とクラスを定義するだけで、それ以外のコードがない場合は、直接アクセスしたときに空白ページが生成されます。
ブラウザからこのファイルへの直接アクセスを許可してください。何もしません。いくつかの関数が定義されていますが、どれも呼び出されないため、実行されません。
<?php
function a() {
// function body
}
function b() {
// function body
}
同じことが、PHPクラスのみを含み、他の何も含まないファイルにも適用されます。
可能な場合は、ファイルをWebディレクトリの外部に置くことをお勧めします。
system
使用します。これは、コードに使用されるパスと競合するためです。私はこれがいらいらします。次のようなことをしてください:
<?php
if ($_SERVER['SCRIPT_FILENAME'] == '<path to php include file>') {
header('HTTP/1.0 403 Forbidden');
exit('Forbidden');
}
?>
次のメソッドを使用することもできますが、別のコード行を追加してリクエストがJavascriptを使用してサーバーからのみであることを確認できる場合を除いて、偽造できるため、欠陥があります。このコードをHTMLコードのBodyセクションに配置すると、エラーが表示されます。
<?
if(!isset($_SERVER['HTTP_REQUEST'])) { include ('error_file.php'); }
else { ?>
ここに他のHTMLコードを配置します
<? } ?>
このように終了してください。そうすれば、エラーの出力は常にbodyセクション内に表示されます。
また、ディレクトリをパスワードで保護し、そこにすべてのphpスクリプトを保持することもできます。もちろん、index.phpファイルを除いて、インクルード時にパスワードはhttpアクセスにのみ必要なので、パスワードは必要ありません。また、そのディレクトリにアクセスするためのパスワードがあるため、必要に応じてスクリプトにアクセスするオプションも提供します。ディレクトリの.htaccessファイルと、ユーザーを認証するための.htpasswdファイルを設定する必要があります。
また、cPanelなどから常にアクセスできるため、通常はこれらのファイルにアクセスする必要がないと思われる場合は、上記のソリューションを使用することもできます。
お役に立てれば
最も簡単な方法は、インクルードをWebディレクトリの外に保存することです。そうすれば、サーバーはそれらにアクセスできますが、外部のマシンはアクセスできません。唯一の欠点は、サーバーのこの部分にアクセスできる必要があることです。利点は、セットアップ、構成、または追加のコード/サーバーのストレスを必要としないことです。
if ( ! defined('BASEPATH')) exit('No direct script access allowed');
仕事はスムーズになります
BASEPATH
const
設定されたindex.php
ツリー構造の一番下に産むファイル。CIはURLを書き換えるので、スクリプトに直接アクセスする必要はありません。
PHPバージョンチェックを追加した前述のソリューション:
$max_includes = version_compare(PHP_VERSION, '5', '<') ? 0 : 1;
if (count(get_included_files()) <= $max_includes)
{
exit('Direct access is not allowed.');
}