Viewed   345 times

Greetings, I'm hoping to make my tiny program secure so that potential malicious users cannot view sensitive files on the server.

    $path = "/home/gsmcms/public_html/central/app/webroot/{$_GET['file']}";


    if(file_exists($path)) {
        echo file_get_contents($path);
    } else {
        header('HTTP/1.1 404 Not Found');
    }

Off the top of my head I know that input such as '../../../../../../etc/passwd' would be trouble, but wondering what other malcious inputs I should expect and how to prevent them.

 Answers

2

realpath() will let you convert any path that may contain relative information into an absolute path...you can then ensure that path is under a certain subdirectory that you want to allow downloads from.

Saturday, October 15, 2022
5

Here are three possible solutions. The second are really just work-arounds that use absolute paths in a clever way.

1: chdir into the correct directory

<?php

// check if the 'StoredProcedure' folder exists in the current directory
// while it doesn't exist in the current directory, move current 
// directory up one level.
//
// This while loop will keep moving up the directory tree until the
// current directory contains the 'StoredProcedure' folder.
//
while (! file_exists('StoredProcedure') )
    chdir('..');

include_once "StoredProcedure/connect.php";
// ...
?>

Note that this will only work if your StoredProcedure folder is in the topmost directory of any files that might need to include the files it contains.

2: Use absolute paths

Now before you say this is not portable, it actually depends on how you implement it. Here's an example that works with Apache:

<?php
include_once $_SERVER['DOCUMENT_ROOT'] . "/StoredProcedure/connect.php";
// ...
?>

Alternatively, again with apache, put the following in your .htaccess in the root directory:

php_value auto_prepend_file /path/to/example.php

Then in example.php:

<?php

define('MY_DOC_ROOT', '/path/to/docroot');

?>

And finally in your files:

<?php
include_once MY_DOC_ROOT . "/StoredProcedure/connect.php";
// ...
?>

3: Set PHP's include_path

See the manual entry for the include_path directive. If you don't have access to php.ini, then this can be set in .htaccess, providing you are using Apache and PHP is not installed as CGI, like so:

php_value include_path '/path/to/my/includes/folder:/path/to/another/includes/folder'
Thursday, August 18, 2022
 
2

I applaud your efforts. You must, friendly community member, consider decoupling your operations.

1) Have one function/routine/class/method for filtering input (filter_input_array(), strip_tags(), str_ireplace(), trim(), etc ...). You may want to create functions that use loops to do filtering. Tricks such as double encoding, one-time-strip-spoofing, and more can defeat single usage of things like strip_tags().

Here is a strip_tags() wrapper method from my Sanitizer class. Notice how it compares the old value to the new value to see if they are equal. If they are not equal, it keeps on using strip_tags(). Although, there is quite of bit of preliminary INPUT_POST / $_POST checking done before this method is executed. Another version of this using trim() is actually executed before this one.

private function removeHtml(&$value)
{    
    if (is_scalar($value)) {
        do {
            $old = $value;
            $value = strip_tags($value);

            if ($value === $old) {
                break;
            }
        } while(1);
    } else if (is_array($value) && !empty($value)) {
        foreach ($value as $field => &$string) {
            do {
                $old = $string;
                $string = strip_tags($string);

                if ($string === $old) {
                    break;
                }
            } while (1);
        }
    } else {
       throw new Exception('The data being HTML sanitized is neither scalar nor in an array.');
    }

    return;
}

2) Have another one for validating input (filter_var_array(), preg_match(), mb_strlen, etc...)

Then, when your data needs to switch contexts ...

A) For databases, use prepared statements (PDO, preferably).

B) For returning / transmitting user input to the browser, escape the output with htmlentities() or htmlspecialchars accordingly.

In terms of magic quotes, the best thing to do is just disable that in the php.ini.

Now, with those various constructs having their own areas of responsibility, all you have to do is manage the flow of logic and data inside of your handler file. This includes providing error messages to the user (when necessary) and handling errors/exceptions.

There is no need to use htmlentities() or htmlspecialchars immediately if the data is going from the HTML form directly into the database. The point of escaping data is to prevent it from being interpreted as executable instructions inside a new context. There is no danger htmlentities() or htmlspecialchars can resolve when passing data to a SQL query engine (that is why you filter and validate the input, and use (PDO) prepared statements).

However, after the data is retrieved from database tables and is directly destined for the browser, ok, now use htmlentities() or htmlspecialchars. Create a function that uses a for or foreach loop to handle that scenario.

Here is a snippet from my Escaper class

public function superHtmlSpecialChars($html)
{
     return htmlspecialchars($html, ENT_QUOTES | ENT_HTML5, 'UTF-8', false);
}

public function superHtmlEntities(&$html)
{
    $html = htmlentities($html, ENT_QUOTES | ENT_HTML5, 'UTF-8', false);
}

public function htmlSpecialCharsArray(array &$html)
{       
    foreach ($html as &$value) {
        $value = $this->superHtmlSpecialChars($value);
    }

    unset($value);
}

public function htmlEntitiesArray(array &$html)
{       
    foreach ($html as &$value) {
        $this->superHtmlEntities($value);
    }

    unset($value);
}

You'll have to tailor your code to your own personal tastes and situation.

Note, if you plan on processing the data before sending it to the browser, do the processing first, then escape with your handy-dandy htmlentities() or htmlspecialchars looping function.

You can do it!

Wednesday, October 12, 2022
 
sudoplz
 
4

You were almost there with your use of the split function. You just needed to join the strings, like follows.

>>> import os
>>> '\'.join(existGDBPath.split('\')[0:-1])
'T:\Data\DBDesign'

Although, I would recommend using the os.path.dirname function to do this, you just need to pass the string, and it'll do the work for you. Since, you seem to be on windows, consider using the abspath function too. An example:

>>> import os
>>> os.path.dirname(os.path.abspath(existGDBPath))
'T:\Data\DBDesign'

If you want both the file name and the directory path after being split, you can use the os.path.split function which returns a tuple, as follows.

>>> import os
>>> os.path.split(os.path.abspath(existGDBPath))
('T:\Data\DBDesign', 'DBDesign_93_v141b.mdb')
Sunday, December 4, 2022
 
1

If you are talking about someone else's server, then the short answer is no. If third parties could read your PHP source code, that would be quite a security hole, since PHP files tend to contain database passwords, hash keys, proprietary algorithms and other goodies that you don't want falling in the wrong hands.

If you are talking about your own server (ie. that you yourself have access to), then there are simple scripts that you can put on the server, that allow you to specify a path to any file on the server and have it returned as plaintext. However, you NEVER EVER want to place such a script on a production server, for the reasons mentioned above.

Monday, November 21, 2022
 
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :