web-dev-qa-db-fra.com

Empêcher l'accès direct à un fichier d'inclusion php

J'ai un fichier php que je vais utiliser exclusivement en tant qu'inclusion. Par conséquent, j'aimerais envoyer une erreur au lieu de l'exécuter quand on y accède directement en tapant l'URL au lieu d'être incluse.

Fondamentalement, je dois faire une vérification comme suit dans le fichier php:

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

Y a-t-il un moyen facile de faire ceci?

148
Alterlife

Le moyen le plus simple pour la situation générique "d'application PHP exécutée sur un serveur Apache que vous puissiez ou non contrôler totalement" est de placer vos inclus dans un répertoire et de refuser l'accès à ce répertoire dans votre fichier .htaccess. Si vous utilisez Apache, épargnez-le dans un fichier nommé ".htaccess" du répertoire que vous ne souhaitez pas voir être accessible:

Deny from all

Si vous avez réellement le contrôle total du serveur (plus courant de nos jours même pour les petites applications que lorsque j'ai écrit cette réponse pour la première fois), la meilleure approche consiste à coller les fichiers que vous souhaitez protéger en dehors du répertoire utilisé par votre serveur Web. . Ainsi, si votre application est dans /srv/YourApp/, configurez le serveur pour qu'il serve les fichiers à partir de /srv/YourApp/app/ et placez les inclus dans /srv/YourApp/includes, afin qu'aucune URL ne puisse y accéder.

153
Chuck

Ajoutez ceci à la page que vous souhaitez inclure uniquement

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

puis sur les pages qui l'incluent ajouter

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

J'ai un fichier dont j'ai besoin pour agir différemment quand il est inclus vs quand on y accède directement (principalement un print() vs return()) Voici un code modifié:

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

Le fichier en cours d'accès est toujours un fichier inclus, d'où le == 1.

104
null

Le meilleur moyen d'empêcher l'accès direct aux fichiers est de les placer en dehors de la racine du document du serveur Web (généralement au niveau supérieur). Vous pouvez toujours les inclure, mais il n'y a aucune possibilité que quelqu'un y accède via une requête http.

Je vais généralement jusqu'au bout et place tous mes fichiers PHP en dehors de la racine du document en dehors du fichier bootstrap - un fichier index.php isolé dans la racine du document qui commence à acheminer le site Web/l'application au complet .

31
Eran Galperin

Une alternative (ou un complément) à la solution de Chuck serait de refuser l’accès aux fichiers correspondant à un modèle spécifique en mettant quelque chose comme ceci dans votre fichier .htaccess.

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

1: Vérification du nombre de fichiers inclus

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

Logic: PHP se ferme si le nombre d'inclusions minimum n'est pas atteint. Notez qu'avant PHP5, la page de base n'était pas considérée comme une inclusion.


2: Définir et vérifier une constante globale

// 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: Si la constante n'est pas définie, l'exécution ne démarre pas à partir de la page de base et PHP s'arrête.


3: autorisation d'adresse à distance

// 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');

L'inconvénient de cette méthode est l'exécution isolée, sauf si un jeton de session est fourni avec la demande interne. Vérifiez via l'adresse de bouclage dans le cas d'une configuration de serveur unique ou une liste blanche d'adresses pour une infrastructure de serveur multiserveur ou à charge équilibrée.


4: autorisation de jeton

Comme pour la méthode précédente, vous pouvez utiliser GET ou POST pour transmettre un jeton d'autorisation au fichier include:

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

Une méthode très compliquée, mais peut-être aussi la plus sûre et la plus polyvalente à la fois, quand elle est utilisée correctement.


5: Configuration spécifique au serveur Web

La plupart des serveurs vous permettent d'attribuer des autorisations pour des fichiers ou des répertoires individuels. Vous pouvez placer tous vos inclus dans de tels répertoires restreints et configurer le serveur pour les refuser.

Par exemple, dans Apache, la configuration est stockée dans le fichier .htaccess. Tutoriel ici .

Remarque Cependant, je ne recommande pas les configurations spécifiques au serveur, car elles sont mauvaises pour la portabilité sur différents serveurs Web. Dans les cas où l'algorithme de refus est complexe ou que la liste des répertoires refusés est assez longue, les sessions de reconfiguration risquent de devenir plutôt macabres. En fin de compte, il est préférable de gérer cela dans le code.


6: Le placement inclut dans un répertoire sécurisé OUTSIDE la racine du site

Préféré par le moins en raison des limitations d'accès dans les environnements de serveur, il s'agit d'une méthode assez puissante si vous avez accès au système de fichiers.

//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");

Logique:

  • L'utilisateur ne peut demander aucun fichier en dehors du dossier htdocs car les liens seraient en dehors de la portée du système d'adresses du site Web.
  • Le serveur php accède au système de fichiers de manière native, et peut donc accéder aux fichiers sur un ordinateur exactement comme un programme normal avec les privilèges requis.
  • En plaçant les fichiers d'inclusion dans ce répertoire, vous pouvez vous assurer que le serveur php pourra y accéder, tandis que la liaison directe est refusée à l'utilisateur.
  • Même si la configuration de l'accès au système de fichiers du serveur Web n'était pas correctement effectuée, cette méthode empêcherait la publication accidentelle de ces fichiers.

Veuillez excuser mes conventions de codage non orthodoxes. Tout commentaire est apprécié.

22
RiA

En fait, mon conseil est de faire toutes ces meilleures pratiques.

  • Placez les documents hors de la racine Web OR dans un répertoire auquel le serveur Web a refusé l'accès AND
  • Utilisez une définition dans vos documents visibles que les documents masqués recherchent:
      if (!defined(INCL_FILE_FOO)) {
          header('HTTP/1.0 403 Forbidden');
          exit;
      }

Ainsi, si les fichiers sont égarés (opération ftp erronée), ils sont toujours protégés.

14
jmucchiello

J'ai eu ce problème une fois, résolu avec:

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

mais la solution idéale consiste à placer le fichier en dehors de la racine du document du serveur Web, comme indiqué dans une autre réponse.

7
mati

Vous feriez mieux de créer une application avec un point d’entrée, c’est-à-dire que tous les fichiers doivent être accessibles à partir de index.php

Placez ceci dans index.php

define(A,true);

Cette vérification doit être exécutée dans chaque fichier lié (via require ou include)

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

Je voulais restreindre l'accès au fichierPHPdirectement, mais aussi pouvoir l'appeler via jQuery $.ajax (XMLHttpRequest). Voici ce qui a fonctionné pour moi.

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

Qu'est-ce que Joomla! do définit une constante dans un fichier racine et vérifie si celle-ci est définie dans les fichiers inclus.

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

ou sinon 

on peut garder tous les fichiers hors de la portée d'une requête http en les plaçant hors du répertoire webroot comme le recommandent la plupart des frameworks comme CodeIgniter. 

ou même en plaçant un fichier .htaccess dans le dossier d'inclusion et les règles d'écriture, vous pouvez empêcher tout accès direct.

4
Pradeesh kumar

Le moyen le plus simple consiste à définir une variable dans le fichier inclus dans les appels, telle que

$including = true;

Ensuite, dans le fichier qui est inclus, vérifiez la variable

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

Outre la méthode .htaccess, j’ai trouvé un motif utile dans divers cadres, par exemple dans Ruby on Rails. Ils ont un répertoire pub/distinct dans le répertoire racine de l’application et les répertoires de la bibliothèque résident dans des répertoires situés au niveau du répertoire. même niveau comme pub /. Quelque chose comme ça (pas idéal, mais vous avez l’idée):

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

Vous configurez votre serveur Web pour utiliser pub/en tant que racine de document. Cela offre une meilleure protection à vos scripts: bien qu’ils puissent accéder à la racine du document pour charger les composants nécessaires, il est impossible d’accéder aux composants à partir d’Internet. Un autre avantage, outre la sécurité, est que tout est au même endroit.

Cette configuration est préférable à la simple création de vérifications dans chaque fichier inclus car le message "accès non autorisé" est un indice pour les attaquants, et il vaut mieux que la configuration .htaccess car il ne repose pas sur une liste blanche: si vous bousillez les extensions de fichier il ne sera pas visible dans les répertoires lib /, conf/etc.

3
bandi

Si plus précisément, vous devriez utiliser cette condition:

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

get_included_files () retourne un tableau indexé contenant les noms de tous les fichiers inclus (si file est beign exécuté, il a été inclus et son nom figure dans le tableau) . Ainsi, lorsque le fichier est directement accédé, son nom est le premier du tableau, tous les autres fichiers du tableau étaient inclus.

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>");
}
?>

placez le code ci-dessus en haut de votre fichier php inclus.

ex:

<?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

Le code suivant est utilisé dans le CMS Flatnux ( http://flatnux.altervista.org ):

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

Ma réponse a une approche quelque peu différente, mais comprend bon nombre des réponses fournies ici. Je recommanderais une approche multi-thématique:

  1. .htaccess et les restrictions Apache à coup sûr
  2. defined('_SOMECONSTANT') or die('Hackers! Be gone!');

CEPENDANT l’approche defined or die comporte un certain nombre d’échecs. Tout d’abord, il est très difficile de tester et de déboguer les hypothèses. Deuxièmement, cela implique un refactoring horriblement ennuyeux et ennuyeux si vous changez d'avis. "Trouver et remplacer!" vous dites. Oui, mais êtes-vous sûr que cela est écrit exactement de la même manière partout, hmmm? Maintenant multipliez cela avec des milliers de fichiers ... o.O

Et puis il y a .htaccess. Que se passe-t-il si votre code est distribué sur des sites où l'administrateur n'est pas si scrupuleux? Si vous ne comptez que sur .htaccess pour sécuriser vos fichiers, vous aurez également besoin: a) d’une sauvegarde, b) d’une boîte de mouchoirs pour sécher vos larmes, c) d’un extincteur pour éteindre les flammes de tout le courrier des personnes en utilisant votre code.

Donc, je sais que la question demande le "plus facile", mais je pense que cela nécessite davantage de "codage défensif".

Ce que je suggère, c'est:

  1. Avant n'importe lequel de vos scripts require('ifyoulieyougonnadie.php'); (noninclude() et en remplacement de defined or die)
  2. Dans ifyoulieyougonnadie.php, effectuez des opérations logiques (recherchez des constantes différentes, un script d'appel, des tests d'hôte local, etc.), puis implémentez votre die(), throw new Exception, 403, etc.

    Je crée mon propre cadre avec deux points d'entrée possibles - le principal index.php (cadre Joomla) et ajaxrouter.php (mon cadre) - donc, en fonction du point d'entrée, je vérifie différentes choses. Si la demande de ifyoulieyougonnadie.php ne provient pas de l'un de ces deux fichiers, je sais que des manigances sont en cours!

    Mais que se passe-t-il si j'ajoute un nouveau point d'entrée? Pas de soucis. Je viens de changer ifyoulieyougonnadie.php et je suis trié, plus "Trouver et remplacer". Hourra!

    Que se passe-t-il si je décide de déplacer certains de mes scripts pour créer un framework différent qui n'a pas les mêmes constantes defined()? ... Hourra! ^ _ ^

J'ai trouvé que cette stratégie rend le développement beaucoup plus amusant et beaucoup moins:

/**
 * 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');

fera le travail en douceur

0
Varshaan

Vous pouvez utiliser le style 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

c'est ce que google utilise dans leurs exemples php voir ici

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

Le stockage de vos fichiers d'inclusion en dehors du répertoire accessible par le Web a été mentionné à plusieurs reprises et constitue certainement une bonne stratégie dans la mesure du possible. Cependant, une autre option que je n’ai pas encore vue mentionnée: assurez-vous que vos fichiers d’inclusion ne contiennent aucun code exécutable . Si vos fichiers d'inclusion se contentent de définir des fonctions et des classes, et n'ont pas d'autre code que celui-ci, ils produiront simplement une page vierge lors d'un accès direct.

Permettez bien sûr d’autoriser l’accès direct à ce fichier à partir du navigateur: il ne fera rien . Il définit certaines fonctions, mais aucune d’elles n’est appelée, donc aucune d’elles ne s'exécute.

<?php

function a() {
    // function body
}

function b() {
    // function body
}

La même chose s'applique aux fichiers qui ne contiennent que PHP classes, et rien d'autre.


C’est quand même une bonne idée de conserver vos fichiers en dehors du répertoire Web, si possible.

  • Vous pourriez désactiver accidentellement PHP, auquel cas votre serveur pourrait envoyer le contenu des fichiers PHP au navigateur, au lieu d'exécuter PHP et d'envoyer le résultat. Cela pourrait entraîner une fuite de votre code (y compris des mots de passe de base de données, des clés d'API, etc.).
  • Les fichiers du répertoire Web s'accroupissent dans les URL que vous pouvez utiliser pour votre application. Je travaille avec un CMS qui ne peut pas avoir une page appelée system, car cela entrerait en conflit avec un chemin utilisé pour le code. Je trouve cela agaçant.
0
TRiG

Ce que vous pouvez également faire est de protéger le répertoire par un mot de passe et de conserver tous vos scripts php, sauf le fichier index.php, car, au moment de l’inclusion, le mot de passe n’est pas requis, il ne sera nécessaire que pour un accès http. Cela vous donnera également la possibilité d'accéder à vos scripts au cas où vous le voudriez, car vous aurez le mot de passe pour accéder à ce répertoire. vous devrez configurer le fichier .htaccess pour le répertoire et un fichier .htpasswd pour authentifier l'utilisateur.

eh bien, vous pouvez également utiliser l’une des solutions fournies ci-dessus si vous estimez que vous n’avez pas besoin d’accéder à ces fichiers normalement, car vous pouvez toujours y accéder via cPanel, etc.

J'espère que cela t'aides

0
RohitG

Faites quelque chose comme:

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

Je n'ai pas trouvé les suggestions avec .htaccess aussi bonnes, car elles pourraient bloquer Tout autre contenu de ce dossier auquel vous pouvez autoriser un utilisateur à accéder, Voici ma solution:

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

je suggère de ne pas utiliser $_SERVER pour des raisons de sécurité.
Vous pouvez utiliser une variable telle que $root=true; dans le premier fichier qui en contient un autre.
et utilisez isset($root) au début du deuxième fichier à inclure. 

0
Mohamad Rostami

Vous pouvez utiliser la méthode suivante ci-dessous bien que, il y ait une faille car elle peut être falsifiée, sauf si vous pouvez ajouter une autre ligne de code pour vous assurer que la requête provient uniquement de votre serveur, soit en utilisant Javascript .. Placez ce code dans la section Body de votre code HTML, de sorte que l'erreur s'affiche.

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

Placez votre autre code HTML ici

<? } ?>

Terminez-le comme ceci, de sorte que le résultat de l'erreur sera toujours affiché dans la section body, si c'est ce que vous voulez.

0
Charming Prince

J'ai trouvé cette solution invariable et uniquement php qui fonctionne à la fois avec http et cli 

Définir une fonction: 

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

Appelez la fonction dans le fichier que vous souhaitez empêcher l'accès direct à: 

forbidDirectAccess(__FILE__);

La plupart des solutions données ci-dessus à cette question ne fonctionnent pas en mode Cli.

0
Ka.

Le moyen le plus simple consiste à stocker vos inclus en dehors du répertoire Web. De cette façon, le serveur y a accès mais pas de machine extérieure. Le seul inconvénient est que vous devez pouvoir accéder à cette partie de votre serveur. L'avantage, c'est qu'il ne nécessite aucune configuration, aucune contrainte supplémentaire du code/serveur.

0
user1391838