LinuxQuestions.org
Review your favorite Linux distribution.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 04-04-2012, 01:05 AM   #1
Xeratul
Senior Member
 
Registered: Jun 2006
Location: UNIX
Distribution: FreeBSD
Posts: 2,357

Rep: Reputation: 213Reputation: 213Reputation: 213
PHP: webpage with a field to save onto the webserver space


Hi, I would like simply using PHP to create a simple field (box) like in attachment, and after click onto OK, it directly save it onto my webserver space.

Which direction would you recommend (or even better a solution code)?

thank you for hints
Attached Thumbnails
Click image for larger version

Name:	Notepad-6.jpg
Views:	20
Size:	56.8 KB
ID:	9382  
 
Old 04-04-2012, 10:02 PM   #2
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
Do you wish to retain all submissions, or should it always update the same bit of information, overwriting previous contents?

For the most part, the question is how you want to store the submitted information.

I prefer files over relational databases for a number of reasons, but only when I can set up dedicated user accounts for the stored files. If you use a web hosting solution, that is usually not possible. (Also, many web hosting providers use NFS but without locking support; you may not be able to modify files using PHP without risking turning it into garbage if two clients happen to modify the same file at the same time.)

If your configuration is such that a PHP script may overwrite itself, attackers may be able to add or rewrite your scripts to obtain any data stored under your account, to include malicious content, or just wipe away your entire site. (I prefer to configure my servers so that all scripts are owned by an administrator account, not by the user account my server uses to run them. That way the scripts cannot modify themselves, or create new files, except in specifically designated directories. But, like I said, most web hosting providers do not support this; you'd need a physical or virtual server to do this.)

Most web hosting providers do provide at least a small relational database, MySQL for example. Since you'll need very little explicit file access then, you have much less risk of allowing an attacker to read files or write to files they should not have access to.

Therefore, in the general case, I'd say it makes most sense to use a relational database.

Perhaps you could tell us exactly what you'd like to accomplish? Maybe you are starting PHP programming, and thought that an address book might make a nice starting point? Or perhaps you have a specific use case you need solved? What kind of web server platform do you happen to have available?
 
Old 04-04-2012, 11:23 PM   #3
Xeratul
Senior Member
 
Registered: Jun 2006
Location: UNIX
Distribution: FreeBSD
Posts: 2,357

Original Poster
Rep: Reputation: 213Reputation: 213Reputation: 213
your post is very interesting

I use a distant server like ssh that gives web and screen

"If your configuration is such that a PHP script may overwrite itself, attackers may be able to add or rewrite your scripts to obtain any data stored under your account" - not cool.






(to be continued)
 
Old 04-05-2012, 02:01 AM   #4
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
Quote:
Originally Posted by Xeratul View Post
"If your configuration is such that a PHP script may overwrite itself, attackers may be able to add or rewrite your scripts to obtain any data stored under your account" - not cool.
To avoid any misunderstanding:

Having a web hosting environment where your scripts can overwrite themselves, or create new scripts the web server will execute, is like running with scissors. If you don't stumble, you probably won't get hurt at all.

The problem is that we humans are not perfect. We stumble. The code we write may occasionally contain bugs that allow an attacker to execute their own code. In PHP, accidentally letting the attacker pick a value with exploitable side effects is more common. For example, your script might use the file name provided with a file upload, but forget to verify or filter the file name for a relative path. If PHP code can create or overwrite existing PHP code, a crafty attacker can then upload their own script file, simply by modifying the file name in the file upload submission -- and then they can run basically any PHP code they want, using your account.

If you do not use PHP file I/O, and disallow file uploads, the risk is minimal.

The scheme I prefer to use protects against basically all of the above, but requires multiple dedicated user accounts.

For example, assume I am user nominal in group animal. This would be the account I login with, and which owns (nominal:animal) my PHP scripts, HTML files, and all media files.

If I had a buddy to share the workload with, she could be user crazee, also in the animal group. We can then use group-based access rights -- that is, we can modify files owned by either person, unless we explicitly deny the right (the default is to allow write access to all members of the same group). The user-owner of the file only tells who "owns", or last uploaded, the file.

PHP and CGI scripts run under a dedicated user account and group, say animal.www:animal.www . All us PHP/CGI admins would either also belong to the animal.www group, or have sudo right to "become" animal.www user, for maintenance purposes.

To allow a PHP or CGI script file access, I normally create a dedicated directory outside the web tree -- that is, not accessible via a web page. The animal.www group would have write access to that directory. (POSIX ACLs are very useful here, since you can also give the animal group of humans full access to that directory.) For e.g. image uploads, I recommend you use GD or ImageMagick to open each uploaded image, and save it to the public directory (perhaps with downscaled thumbnails), in order to strip any extraneous information from uploaded files. Obviously you should disable script execution completely for such directories!

For sensitive operations, like login and password management, I do prefer to use a yet another dedicated user account, say animal.sec:animal.sec. If user animal.sec also belongs to the animal.www group, and file access rights are determined exclusively using group rights like I outlined above, the scripts running as animal.sec:animal.sec can do everything scripts running as animal.www:animal.www can, but also have access to private data not accessible to the latter. (For example, credentials to access passwords and other privileged information.) Consider this a "super script" user -- but still completely limited by what files and directories humans will allow it access to.

Mostly this all is risk management. Perfect code does not need any of the above. I just don't have perfect code! Compartmentalizing access to information using dedicated user accounts in above hierarchical fashion turns out to be pretty easy in real life if you maintain your own server or server image, especially if you are a team working together. (If you have task-dedicated accounts like webmaster, it is a different story. My way is designed to work when people log in using their own actual user accounts to do maintenance, mostly because that's what people tend to do.)

Finally, if your web server configuration is limited to only fully trusted administrators, you can use server-added custom request headers (or environment variables, but only if using FastCGI!) to pass sensitive information like database passwords from the server to only specific scripts. This lets you limit the visibility of the sensitive information to just a few scripts, thus reducing the possible number of security vulnerabilities. Instead of some script file or "hidden" file, the sensitive information is saved in privileged configuration files not at all accessible to the web server. (For example, Apache reads its configuration files using superuser rights, not as the user and group specified in its configuration file.) Why let all scripts have access to all information, when they don't need it?

Ahem. Sorry for the rant.

If you want the simplest possible example, I can show how it is done, but I will insist on describing its inherent security risks

Hope you find this interesting,
 
Old 04-12-2012, 02:41 PM   #5
Xeratul
Senior Member
 
Registered: Jun 2006
Location: UNIX
Distribution: FreeBSD
Posts: 2,357

Original Poster
Rep: Reputation: 213Reputation: 213Reputation: 213
Thank you. Thus it would imply that note php type php codes are relatively not suited. How would you make it better with still remaining simple code?

Code:
<?
define("DEFAULT_FILE", "txt.txt");  



if ($_GET[file] == "") 
    $file = DEFAULT_FILE;
else
    $file = $_GET[file];

if ($_POST[update] == "true") {
    $fh = fopen($file, 'w') or die("Can't open file.");
    fwrite($fh, stripslashes($_POST[body]));
    fclose($fh);
}


if ($_POST[bsubmit]=="Save")
{
    $fh = fopen($file, 'w') or die("Can't open file.");
    fwrite($fh, stripslashes($_POST[body]));
    fclose($fh);
echo ' <span style="font-weight: bold" > '  ;
echo '    Saved !     ' ;
echo '</span> ' ;
echo '</div> ' ;
echo '<div style="text-align: left;"> '  ;


}



?>
<html><head><title> Insert </title></head><body>
<center><table width=400><tr><td style='border: 2px dashed #003b53; padding:10px; font-family:verdana; font-size:10px; color: #003b53;' align='center'>
Editing: <i><?=$file?></i><br><br>
<form action='<?=$PHP_SELF?>?file=<?=$file?>' method='post'>


<form action='<?=$PHP_SELF?>?file=<?=$file?>' method='post'>
<textarea name='body'  rows="25" cols="100"  style="font-family: Verdana; padding: 5px; background-color: LightYellow"   ><?
if (file_exists($file))
    readfile($file);
else
    $message = "The file ".$file." does not exist and will<br>be created when you click Save.<br><br>";
?></textarea><br><br>
<?=$message?> 


<FORM action="pad.php" method="post">
   
    <INPUT type="submit" name="bsubmit" value="Save">
    

</FORM>



</form>
</td></tr></table></center>
</body></html>
 
Old 04-13-2012, 11:34 AM   #6
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
Quote:
Originally Posted by Xeratul View Post
Thank you. Thus it would imply that note php type php codes are relatively not suited. How would you make it better with still remaining simple code?
Wow. That example suffers exactly from the problem I mentioned. If you add ?file=/full/path/to/script.php to the script URL, and you run this on a typical web hosting account, you can overwrite the script itself. Just.. wow.

Here is what I'd do:
  • Create a designated directory for the uploaded snippets/files.
    I prefer to put the files outside the web trees entirely.

    If you need to publish them, make sure your HTTP server will not execute scripts in that directory. At minimum, you can use a filename suffix that your HTTP server will not interpret as a script file. However, if you detect file type by the file contents (e.g. Apache mod_mime_magic), you will have to tell your HTTP server to handle all files in that directory as static files (e.g. in Apache using ForceType directive).
  • Filter specified file names.
    In the example code, I only allow file names I know to be safe. I don't allow any suffix, as I'll be hardcoding .txt suffix.
  • Filter input content.
    Make sure the input is what it should be. At minimum, filter out unwanted input (like control characters).
    For text this is not that important, but for file uploads you really should verify that the file is whatever it should be.
  • I do not allow the script to create new files, only access existing files.
    I do this for all unsecured scripts to avoid someone filling up the disk space.

Here is the example code. I'll try to add descriptive comments, but if there is anything you need further clarification with, just ask.
Code:
<?PHP
    /* Data file directory. Modify to match your setup. */
    define('DATA_PATH', '/home/xeratul/public_data/');

    /* 'file' GET or POST parameter specified the data file. */
    $filename = @$_REQUEST['file'];

    /* Is the file name acceptable? */
    if (preg_match('/^[A-Za-z][-0-9A-Z_a-z]*$/s', $filename))
        $filename = $filename;
    else
        $filename = 'default';

    /* Combine the data path and the file name. */
    $filepath = rtrim(DATA_PATH, '/') . '/' . $filename . '.txt';

    /* 'save' POST parameter indicates save operation. */
    if (strlen(@$_POST['save']) > 0) {
        $saving = TRUE;

        /* Remove ASCII control chars from 'text' POST parameter. */
        $content = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F]+/s', '', @$_POST['text']);

        /* Check if the file exists. */
        if (@file_exists($filepath) === TRUE) {
            $exists = TRUE;

            /* Save the file. Check success. */
            if (@file_put_contents($filepath, $content, LOCK_EX) === FALSE)
                $saved = FALSE;
            else
                $saved = TRUE;

        } else {
            /* File does not exist. Cannot save. */
            $exists = FALSE;
            $saved = FALSE;
        }
    } else {
        $saving = FALSE;
        $saved = FALSE;

        /* No save, so load. */
        $content = @file_get_contents($filepath);

        /* Did the file exist? */
        $exists = ($content !== FALSE);
    }

    /* At this point, we have:
     *  $content    the text area contents, unsafe for HTML
     *  $filename   the (base) name of the file used
     *  $exists     TRUE if the specified file exists
     *  $saving     TRUE if we tried to save modified contents
     *  $saved      TRUE if the contents were saved successfully
    */

    /* Helper function: echo the string for HTML and form input.
    */
    function value($unsafe) {
        echo htmlentities($unsafe, ENT_COMPAT, 'utf-8');
    }

?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
 "http://www.w3.org/TR/html4/loose.dtd">
<html>
 <head>
  <title> PHP Example: Persistent text </title>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <style type="text/css">

   html, body {
      font-size: 100%;
      font-family: serif;
      font-weight: normal;
      font-style: normal;
      padding: 0 0 0 0;
      border: 0 none;
      margin: 0 auto auto auto;
      color: #000000;
      background: #f7f7f7;
   }

   div.body {
      width: 40em;
      padding: 0 0 0 0;
      border: 0 none;
      margin: 0 auto 0 auto;
   }

   table {
      padding: 0.5em 1em 0.5em 1em;
      border: 0 none;
      margin: 0 0 0 0;
      border-collapse: collapse;
   }

   td, th {
      font-size: 100%;
      font-weight: normal;
      vertical-align: middle;
      border: 0 none;
      margin: 0 0 0 0;
   }
   th {
      text-align: right;
      padding: 0.1em 0.1em 0.1em 0.5em;
   }
   td {
      text-align: left;
      padding: 0.1em 0.5em 0.1em 0.1em;
   }

   textarea, input.full {
      font-family: monospace;
      font-size: 100%;
      font-weight: normal;
      padding: 0.1em 0.5em 0.1em 0.5em;
      border: 1px solid #cccccc;
      margin: 0.1em 0.5em 0.1em 0.5em;
   }

   input.left {
      float: left;
      text-align: center;
      width: 45%;
   }
   input.right {
      float: right;
      text-align: center;
      width: 45%;
   }

   .error {
      font-style: italic;
      font-weight: bold;
      color: #cc0000;
   }

   .ok {
      font-style: italic;
      font-weight: bold;
      color: #0000cc;
   }

  </style>
 </head>
 <body>
  <div class="body">
   <form method="POST" action="<?PHP echo @$_SERVER['REQUEST_URI']; ?>"
         accept-charset="UTF-8">
    <fieldset>
     <legend>Persistent text</legend>
     <table border="0" frame="void" rules="none">
      <tr>
       <th><label for="form_filename">File:</label></th>
       <td><input class="full" type="text" name="file" id="form_filename" size="20" value="<?PHP value($filename); ?>"><?PHP
        if ($saved)
            echo ' <span class="ok">saved successfully</span>';
        else if (!$exists)
            echo ' <span class="error">not found</span>';
        else if ($saving)
            echo ' <span class="error">write error</span>';
?></td>
      </tr>
      <tr>
       <th><label for="form_text">Content:</label></th>
       <td><textarea name="text" id="form_text" rows="10" cols="40"><?PHP value($content); ?></textarea></td>
      </tr>
      <tr>
       <th>&nbsp;</th>
       <td>
        <input class="left" type="submit" name="load" value="Revert">
        <input class="right" type="submit" name="save" value="Save">
        <br clear="all">
       </td>
      </tr>
     </table>
    </fieldset>
   </form>
  </div>
 </body>
</html>
There is only 37 lines of PHP code, above. The rest is comments, CSS, and HTML. Note how the only string I use as-is is $_SERVER['REQUEST_URI'] (the URL to this script, as determined by the HTTP server); everything else is checked or escaped.

Note: The above is only partially tested; I'm too lazy to add PHP support to my current development environment. Sorry


I prefer to keep the major logic at the start of the file. In fact, I prefer to split the HTML output to separate files, one for success, and one for form display (with error messages). This is very easy: simply split the HTML into separate files, say form-saved.inc and form.inc , and replace the HTML above with
Code:
    if ($saved) {
        @include('form-saved.inc');
        exit(0);
    } else {
        @include('form.inc');
        exit(0);
    }
All the variables are available in those two files, too; they should only have the minimum PHP necessary to inject the strings (set up by the main .php file) into the HTML output. Preferably using custom functions like value() above, to make sure the output is safe/sane.

Any questions?
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
How can I save my time not to do the same repetitive job in a webpage to fill a form pokhraa Linux - Software 2 12-24-2011 04:39 PM
Any idea where to find PHP code for a sharing Notepad webpage with auto-save? frenchn00b Programming 1 11-30-2009 08:09 PM
php question, how do I get a return from a field within a field? cherrington Programming 11 04-29-2009 01:27 AM
I don't want the web page to save the text on field. RMLinux Linux - Newbie 2 09-30-2008 10:42 PM
webserver running more than one webpage? IonMarais Linux - Newbie 2 10-09-2006 02:55 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 03:29 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration