How to use file_get_contents safely?

2020-07-24 06:22发布

问题:

I am making a basic PHP source viewer for my blog's example code folder.

<?php

if (isset($_GET['file']))
{
    header('Content-type: text/plain');
    $filename = realpath($_GET['file']);
    if (startsWith($filename, dirname(__FILE__)))
    {
        echo file_get_contents($filename);
    }
}

function startsWith($haystack, $needle)
{
    $length = strlen($needle);
    return (substr($haystack, 0, $length) === $needle);
}

?>

Is what I have here sufficient that it will never allow a file outside the directory in which this script is located, or subdirectories of this script's directory, to be viewed? I'm guessing there's a better solution than startsWith too, for checking whether a path is a descendant of a particular directory?

回答1:

It's going to be safe, yes. The realpath part is what you have to do, and you are doing it. This code does what it's supposed to just fine.



回答2:

You maybe reduce the input to a filename (see finfo) and specify the directory to search in, if it's the same directory every time - so you don't need to check via startsWith().

If you only want to show PHP-sourcecode, try to enable *.phps-file-handling within your webserver. See: https://serverfault.com/questions/62410/apache-htaccess-phps



回答3:

As an aside, look into using strncmp instead of your custom startsWith function.



回答4:

If I was to approach a project like this I would:

Use a combination of your solution & htaccess to mask the original filename as having:

http://example.com/viewsource.php?file=./project1/index.php

would be just too obvious and tempting to mess around with, using htaccess you could have:

http://example.com/source/project1/index.php

that points too

h1ddEnfIlEs/viewSource/index.php?file=$1&folder=$2

RewriteRule ^source/([a-z0-9]+)/([a-z0-9]+).php$ h1ddEnfIlEs/viewSourceScript/index.php?file=$2&project=$1

Then with the source viewer h1ddEnfIlEs/viewSourceScript/index.php

<?php 
if(
is_dir('./h1ddEnfIlEs/'.$_GET['project'].'/')===true && 
is_file('./h1ddEnfIlEs/'.$_GET['project'].'/'.basename($_GET['file']))
){
    highlight_file('./h1ddEnfIlEs/'.$_GET['project'].'/'.basename($_GET['file']));
}
?>


标签: php security