У моего webapp есть buch модулей. Каждый модуль имеет «основной» 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']
но мне было интересно, есть ли какой-то элегантный способ сделать это.
Одним из элегантных способов является размещение всех ваших файлов, доступ к которым можно получить только через веб-каталог .
Скажите, что ваш веб-каталог / 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, если она у вас не пустая, чтобы включить в нее свой каталог).
Единственный файл, который вам действительно нужен в вашем веб-каталоге, – это то, что мы называем bootstrap (index.php), с хорошим правилом перезаписи или хорошим управлением URL-адресами, вы можете ограничить все ваши запросы в приложении этим файлом, это будет хорошо отправной точкой для обеспечения безопасности.
Я искал способ определить, был ли файл включен или вызван напрямую, все из файла. В какой-то момент в моих поисках я прошел через эту тему. Проверяя различные другие темы на этом и других сайтах и страницах из руководства 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 )
Я знаю, что «немного» поздно ответить на главный вопрос, но я догадался, что он может быть полезен любому, кто находится в той же ситуации, что и я, и которая также проходит мимо.
Один из популярных способов убедиться, что модули не вызываются напрямую, – это определение константы в главном скрипте и проверка этой константы в модуле.
// index.php define("LEGIT_REQUEST", true); // in each module if (!defined("LEGIT_REQUEST")) die ("This module cannot be called directly.");
Для полноты, другая возможность заключается в перемещении таких файлов в каталог, который не является общедоступным. Однако некоторые панели управления, используемые хостинг-провайдерами, делают это невозможным. В этом случае, если вы используете Apache, вы можете поместить файл .htaccess
в каталог:
# # Private directory # Order allow,deny Deny from all
Общим методом является добавление этого в основной модуль (до включения)
define('TEST', true);
и добавить что-то подобное в первой строке каждого подмодуля
if (!defined('TEST')) { die('Do not cheat.'); }
Альтернативой определению константы и ее проверке является простое размещение файлов, которые index.php включает вне корневой области документа. Таким образом, пользователь не может напрямую обращаться к ним через ваш веб-сервер. Это также, безусловно, самый безопасный способ, если ваш веб-сервер в будущем будет иметь конфигурационную ошибку, например. отображает файлы PHP как обычный текст.
Вы можете define('SOMETHING', null)
в clientes.php, а затем проверить if (!defined('SOMETHING')) die;
в модулях.
global.php
if(!defined("in_myscript")) { die("Direct access forbidden."); }
module.php
define("in_myscript", 1); include("global.php");
Общий способ, который работает без необходимости определять константу или использовать htaccess или использовать определенную структуру каталогов или зависеть от массива $ _SERVER, который теоретически может быть изменен, заключается в том, чтобы запускать каждый файл с единственным доступом (без прямого доступа) с этим кодом:
<?php $inc = get_included_files(); if(basename(__FILE__) == basename($inc[0])) exit();
Как практика привычки, у меня есть консольный класс, созданный для отправки сообщений, ошибок и т. Д. Для консоли с FirePHP. Внутри метода write () метода класса Console у меня есть проверка, чтобы увидеть, есть ли $ _REQUEST [debug] == 1, таким образом я не подвергаю ошибки пользователям, если что-то появляется на производстве, и им нужно будет знать, что запрос переменная – это доступ к отладочной информации.
В верхней части каждого файла я добавляю:
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, ''); } }
Короткий и простой (для CLI):
if (__FILE__ == realpath($argv[0])) main();