在PHP中保护路径

tjm*_*tjm 5 php security

我正在编写一些PHP,它需要一些路径到不同的内容目录,并使用它们以后包含页面的各个部分.我正在努力确保路径看起来像它们一样,并且它们都没有违反应用程序的规则.哪个是,

  1. PRIVATEDIR(相对于DOCUMENT_ROOT)定义必须高于DOCUMENT_ROOT.
  2. CONTENTDIR(相对于PRIVATEDIR)定义必须位于下方PRIVATEDIR,不得返回DOCUMENT_ROOT.
  3. 其余*DIRS的(相对于CONTENTDIR)定义必须位于下方CONTENTDIR

我在单例控制器类中设置了一些默认值,然后用户将要覆盖的路径数组传递给此类构造函数.然后我想要理智地检查它们以确保它们遵守上述规则.继承人我是如何开始的...

编辑: 请注意我error_reporting在下面的代码中的使用,然后不要自己做!我误解了这个命令是如何工作的.如果你想知道为什么,请参阅stealthyninja和评论Shrapnel的评论(并感谢他们指出这一点).

private $opts = array( // defaults
   'PRIVATEDIR'   => '..',        // relative to document root
   'CONTENTDIR'   => 'content',   // relative to private dir
   ...
   ...
);

private function __construct($options) { //$options is the user defined options
    error_reporting(0);
    if(is_array($options)) {
        $this->opts = array_merge($this->opts, $options);
    }

    if($this->opts['STATUS']==='debug') {
        error_reporting(E_ALL | E_NOTICE | E_STRICT);
    }

    $this->opts['PUBLICDIR']  = realpath($_SERVER['DOCUMENT_ROOT'])
                                        .DIRECTORY_SEPARATOR;
    $this->opts['PRIVATEDIR'] = realpath($this->opts['PUBLICDIR']
                                        .$this->opts['PRIVATEDIR'])
                                        .DIRECTORY_SEPARATOR;
    $this->opts['CONTENTDIR'] = realpath($this->opts['PRIVATEDIR']
                                        .$this->opts['CONTENTDIR'])
                                        .DIRECTORY_SEPARATOR;
    $this->opts['CACHEDIR']   = realpath($this->opts['CONTENTDIR']
                                        .$this->opts['CACHEDIR'])
                                        .DIRECTORY_SEPARATOR;
    $this->opts['ERRORDIR']   = realpath($this->opts['CONTENTDIR']
                                        .$this->opts['ERRORDIR'])
                                        .DIRECTORY_SEPARATOR;
    $this->opts['TEMPLATEDIR' = realpath($this->opts['CONTENTDIR']
                                        .$this->opts['TEMPLATEDIR'])
                                        .DIRECTORY_SEPARATOR;

   ...
   ...
   ...


    // then here I have to check that PRIVATEDIR is above PUBLICDIR
    // and that all the rest remain within private dir and don't drop 
    // down into (or below) PUBLICDIR again. And die with an error if
    // they don't conform.
}
Run Code Online (Sandbox Code Playgroud)

事情是这似乎要做很多工作,尤其是每次访问页面时必须运行,然后才能执行任何其他操作(例如检查我正在服务的页面的缓存版本),路径基本上是静态的.

我的一部分是认为网站的维护者(现在我)应该知道他们提供的路径,并且应该检查他们是否符合规则.但是(我认为)我更明智的一面是说,不,我应该同样负责检查路径是否符合,因为事故确实发生(特别是当网站增长/改变/获得新的维护者......)和如果他们能够被抓住,在安全关键的环境中,就没有理由不抓住他们.

所以,我几乎决定要检查这些路径,问题是我的方法有多好?这感觉就像是次优的解决方案.你会如何改进它或你会建议什么替代品?有没有解决每次页面加载时必须这样做的问题,并且只是在配置发生变化时才这样做?(这将是理想的,但我不认为是微不足道的).

谢谢.

Mic*_*rov 1

使用 strpos 查找子字符串怎么样?这不是最优雅的解决方案,但如果您只想为已经在网站上拥有大量权力的人提供一些基本的保护。我将这样做:

// PRIVATEDIR already includes PUBLICDIR at this point
if(strpos($this->opts['PRIVATEDIR'],$this->opts['PUBLICDIR']) !== 0) {
die('ERROR: '.$this->opts['PRIVATEDIR'].' must be located in .'$this->opts['PUBLICDIR']);
}
Run Code Online (Sandbox Code Playgroud)

请注意,三元组不等于,这确保 PUBLICDIR 出现在 PRIVATEDIR 字符串的位置 0,而不是简单地找不到它或在字符串中的其他位置。另外,您应该检查它们是否相同(PUBLICDIR!= PRIVATEDIR),因为您可以将其设置为“./test/../”,这将使您返回“.”。