Programing

PHP 포함 파일에 직접 액세스 방지

crosscheck 2020. 6. 5. 18:56
반응형

PHP 포함 파일에 직접 액세스 방지


포함으로 독점적으로 사용할 PHP 파일이 있습니다. 따라서 포함되지 않고 URL을 입력하여 직접 액세스 할 때 오류를 실행하는 대신 오류를 발생시키고 싶습니다.

기본적으로 PHP 파일에서 다음과 같이 확인해야합니다.

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

이 작업을 수행하는 쉬운 방법이 있습니까?


일반적인 "완전히 제어 할 수도 있고 아닐 수도있는 Apache 서버에서 실행되는 일반적인 PHP 앱"의 가장 쉬운 방법은 디렉토리에 포함을 넣고 .htaccess 파일에서 해당 디렉토리에 대한 액세스를 거부하는 것입니다. 사람들이 인터넷 검색의 어려움을 피하기 위해 Apache를 사용하는 경우 액세스하지 않으려는 디렉토리에 ".htaccess"라는 파일에 파일을 넣으십시오.

Deny from all

실제로 서버를 완전히 제어 할 수 있다면 (이 답변을 처음 쓸 때보 다 작은 앱에서도 더 일반적입니다) 가장 좋은 방법은 웹 서버가 제공하는 디렉토리 외부에서 보호하려는 파일을 고정하는 것입니다 . 따라서 앱이에있는 경우 /srv/YourApp/서버가 파일을 제공 /srv/YourApp/app/하고 포함을 넣 도록 설정하십시오 /srv/YourApp/includes. 따라서 문자 그대로 액세스 할 수있는 URL이 없습니다.


포함시키고 자하는 페이지에 추가하십시오

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

그런 다음 포함 된 페이지에서

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

포함 된 경우와 직접 액세스 한 경우 (주로 print()vs return()) 다르게 행동 해야하는 파일이 있습니다. 수정 된 코드는 다음과 같습니다.

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

액세스되는 파일은 항상 포함 된 파일이므로 == 1입니다.  


파일에 직접 액세스하지 못하게하는 가장 좋은 방법은 파일을 웹 서버 문서 루트 외부 (일반적으로 한 수준 위)에 두는 것입니다. 여전히 포함 할 수 있지만 http 요청을 통해 누군가가 액세스 할 가능성은 없습니다.

나는 보통 끝까지 가고 모든 웹 사이트 / 애플리케이션을 라우팅하기 시작하는 문서 루트의 고독한 index.php- 부트 스트랩 파일을 제외하고 모든 PHP 파일을 문서 루트 외부에 배치한다 .


Chuck 솔루션의 대안 (또는 보완)은 .htaccess 파일에 이와 같은 것을 넣어 특정 패턴과 일치하는 파일에 대한 액세스를 거부하는 것입니다

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

1 : 포함 된 파일 수 확인

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

논리 : 최소 포함 횟수에 맞지 않으면 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');

논리 : 상수가 정의되어 있지 않으면 기본 페이지에서 실행이 시작되지 않아 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 : 웹 서버 별 구성

대부분의 서버에서는 개별 파일 또는 디렉토리에 대한 권한을 할당 할 수 있습니다. 모든 포함을 이러한 제한된 디렉토리에 배치하고 서버가이를 거부하도록 구성 할 수 있습니다.

예를 들어 APACHE에서 구성은 .htaccess파일에 저장 됩니다. 여기 튜토리얼 .

참고 서로 다른 웹 서버에서 휴대 나쁜 때문에 서버 별 구성 날에 의해 권장하지 않습니다 그러나 것을. 거부 알고리즘이 복잡하거나 거부 된 디렉토리 목록이 큰 경우에는 재구성 세션 만 다소 소중하게 만들 수 있습니다. 결국 코드에서 이것을 처리하는 것이 가장 좋습니다.


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

논리:

  • htdocs링크가 웹 사이트 주소 시스템의 범위를 벗어나므로 사용자는 폴더 외부의 파일을 요청할 수 없습니다 .
  • PHP 서버는 기본적으로 파일 시스템에 액세스하므로 필요한 권한이있는 일반 프로그램처럼 컴퓨터의 파일에 액세스 할 수 있습니다.
  • 포함 파일을이 디렉토리에두면 PHP 서버가 해당 파일에 액세스 할 수 있고 핫 링크는 사용자에게 거부됩니다.
  • 웹 서버의 파일 시스템 액세스 구성이 제대로 수행되지 않은 경우에도이 방법은 해당 파일이 실수로 공개되는 것을 방지합니다.

정통 코딩 규칙을 변명하십시오. 모든 의견을 부탁드립니다.


실제로 내 조언은 이러한 모범 사례를 모두 수행하는 것입니다.

  • 문서를 웹 루트 외부에 두거나 웹 서버가 액세스를 거부 한 디렉토리에 넣습니다.
  • 숨겨진 문서에서 확인할 수있는 정의 된 문서를 다음과 같이 정의하십시오.
      if (!defined(INCL_FILE_FOO)) {
          header('HTTP/1.0 403 Forbidden');
          exit;
      }

이런 식으로 파일이 잘못 배치 된 경우 (잘못된 FTP 작업) 여전히 보호됩니다.


나는이 문제를 한 번 겪었다.

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

그러나 이상적인 해결책은 다른 답변에서 언급 한 것처럼 파일을 웹 서버 문서 루트 외부에 배치하는 것입니다.


하나의 진입 점으로 응용 프로그램을 빌드하는 것이 좋습니다. 즉 모든 파일은 index.php에서 도달해야합니다.

이것을 index.php에 넣으십시오.

define(A,true);

이 검사는 링크 된 각 파일에서 실행해야합니다 (필수 또는 포함을 통해).

defined('A') or die(header('HTTP/1.0 403 Forbidden'));

가장 쉬운 방법은 호출에 포함하는 파일에 일부 변수를 설정하는 것입니다.

$including = true;

그런 다음 포함되는 파일에서 변수를 확인하십시오.

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

무슨 줌라! 루트 파일에 상수를 정의하고 포함 된 파일에 상수가 정의되어 있는지 확인합니다.

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

그렇지 않으면

CodeIgniter와 같은 대부분의 프레임 워크에서 권장하는 것처럼 웹 루트 디렉토리 외부에 파일을 배치하여 모든 파일을 http 요청의 범위 밖에 유지할 수 있습니다.

또는 include 폴더 내에 .htaccess 파일을 넣고 규칙을 작성하여 직접 액세스하지 못하게 할 수 있습니다.


debug_backtrace() || die ("Direct access not permitted");

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;
    }
}

.htaccess 방법 외에도 다양한 프레임 워크 (예 : 루비 온 레일)에서 유용한 패턴을 보았습니다. 응용 프로그램 루트 디렉토리에는 별도의 pub / 디렉토리가 있으며 라이브러리 디렉토리는 pub / 와 동일한 레벨의 디렉토리에 있습니다. 이와 같은 것 (이상적이지는 않지만 아이디어를 얻음) :

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

pub /를 문서 루트로 사용하도록 웹 서버를 설정했습니다. 이를 통해 스크립트를보다 효과적으로 보호 할 수 있습니다. 스크립트는 문서 루트에서 접근하여 필요한 구성 요소를로드 할 수 있지만 인터넷에서 구성 요소에 액세스하는 것은 불가능합니다. 보안 외에 다른 이점은 모든 것이 한 곳에 있다는 것입니다.

This setup is better than just creating checks in every single included file because "access not permitted" message is a clue to attackers, and it is better than .htaccess configuration because it is not white-list based: if you screw up the file extensions it will not be visible in the lib/, conf/ etc. directories.


If more precisely, you should use this condition:

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

get_included_files() returns indexed array containing names of all included files (if file is beign executed then it was included and its name is in the array). So, when the file is directly accessed, its name is the first in the array, all other files in the array were included.


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

place the code above in the top of your included php file.

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

The following code is used in the Flatnux CMS (http://flatnux.altervista.org):

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

I found this php-only and invariable solution which works both with http and cli :

Define a function :

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

Call the function in the file you want to prevent direct access to :

forbidDirectAccess(__FILE__);

Most of the solutions given above to this question do not work in Cli mode.


if (basename($_SERVER['PHP_SELF']) == basename(__FILE__)) { die('Access denied'); };

My answer is somewhat different in approach but includes many of the answers provided here. I would recommend a multipronged approach:

  1. .htaccess and Apache restrictions for sure
  2. defined('_SOMECONSTANT') or die('Hackers! Be gone!');

HOWEVER the defined or die approach has a number of failings. Firstly, it is a real pain in the assumptions to test and debug with. Secondly, it involves horrifyingly, mind-numbingly boring refactoring if you change your mind. "Find and replace!" you say. Yes, but how sure are you that it is written exactly the same everywhere, hmmm? Now multiply that with thousands of files... o.O

And then there's .htaccess. What happens if your code is distributed onto sites where the administrator is not so scrupulous? If you rely only on .htaccess to secure your files you're also going to need a) a backup, b) a box of tissues to dry your tears, c) a fire extinguisher to put out the flames in all the hatemail from people using your code.

So I know the question asks for the "easiest", but I think what this calls for is more "defensive coding".

What I suggest is:

  1. Before any of your scripts require('ifyoulieyougonnadie.php'); (not include() and as a replacement for defined or die)
  2. In ifyoulieyougonnadie.php, do some logic stuff - check for different constants, calling script, localhost testing and such - and then implement your die(), throw new Exception, 403, etc.

    I am creating my own framework with two possible entry points - the main index.php (Joomla framework) and ajaxrouter.php (my framework) - so depending on the point of entry, I check for different things. If the request to ifyoulieyougonnadie.php doesn't come from one of those two files, I know shenanigans are being undertaken!

    But what if I add a new entry point? No worries. I just change ifyoulieyougonnadie.php and I'm sorted, plus no 'find and replace'. Hooray!

    What if I decided to move some of my scripts to do a different framework that doesn't have the same constants defined()? ... Hooray! ^_^

I found this strategy makes development a lot more fun and a lot less:

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

Do something like:

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

You can use the following method below although, it does have a flaw, because it can be faked, except if you can add another line of code to make sure the request comes only from your server either by using Javascript. You can place this code in the Body section of your HTML code, so the error shows there.

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

Place your other HTML code here

<? } ?>

End it like this, so the output of the error will always show within the body section, if that's how you want it to be.


i suggest that don't use of $_SERVER for security reasons .
You can use a variable like $root=true; in first file that included another one.
and use isset($root) in begin of second file that be included.


What you can also do is password protect the directory and keep all your php scripts in there, ofcourse except the index.php file, as at the time of include password won't be required as it will be required only for http access. what it will do is also provide you the option to access your scripts in case you want it as you will have password to access that directory. you will need to setup .htaccess file for the directory and a .htpasswd file to authenticate the user.

well, you can also use any of the solutions provided above in case you feel you don't need to access those files normally because you can always access them through cPanel etc.

Hope this helps


The easiest way is to store your includes outside of the web directory. That way the server has access to them but no outside machine. The only down side is you need to be able to access this part of your server. The upside is it requires no set up, configuration, or additional code/server stress.


<?php       
$url = 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
  if (false !== strpos($url,'.php')) {
      die ("Direct access not premitted");
  }
?>

I didn't find the suggestions with .htaccess so good because it may block other content in that folder which you might want to allow user to access to, this is my solution:

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

if ( ! defined('BASEPATH')) exit('No direct script access allowed');

will do the job smooth


You can use phpMyAdmin Style:

/**
 * block attempts to directly run this script
 */
if (getcwd() == dirname(__FILE__)) {
    die('Attack stopped');
}

this is what google uses in their php examples see here

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

참고URL : https://stackoverflow.com/questions/409496/prevent-direct-access-to-a-php-include-file

반응형