Vodič za PHP bezbednost (PHP Security Guide): Deljeni hosting (Shared Hosts)


< PreviousNext >O (About)Sesije

Izloženi podaci sesija (Exposed Session Data)

Na deljenom hostingu, bezbednost jednostavno nije toliko jaka koliko je na privatnom hostingu. Ovo je jedan od kompromisa za jeftinije troškove.

Jedan posebno ranjiv aspekat deljenog hostinga je postojanje deljenog smeštanja sesija. Po podrazumevanim podešavanjima, PHP smešta poodatke o sesiji u /tmp, i ovo je tačno za sve. Otkrićete da se većina ljudi drži podrazumevanih podešavanja za mnoge stvari, ni sesije nisu izuzetak. Srećom, ne mogu svi čitati fajlove sesija, zato što su oni čitljivi samo od strane web servera:

$ ls /tmp
total 12
-rw-------  1  nobody  nobody  123 May 21 12:34 sess_dc8417803c0f12c5b2e39477dc371462
-rw-------  1  nobody  nobody  123 May 21 12:34 sess_46c83b9ae5e506b8ceb6c37dc9a3f66e
-rw-------  1  nobody  nobody  123 May 21 12:34 sess_9c57839c6c7a6ebd1cb45f7569d1ccfc
$

Na žalost, dosta je jednostavno napisati PHP skript da čita ove fajlove, i zato što se korisnik vodi kao nobody (ili kakav god korisnik koji web server koristi), ima sve neophodne privilegije.

Direktiva safe_mode može sprečiti ovo i slične bezbednosne brige, ali s obzirom da se ovo odnosi samo na PHP, ne rešava koren problema. Napadač može iskoristiti druge jezike.

Šta je bolje rešenje? Nemojte koristiti isto mesto čuvanja kao svi ostali. Poželjno, je čuvati ih u bazi podataka gde su parametri pristupa jedinstveni za vaš nalog. Da bi uradili ovo, jednostavno koristite funkciju session_set_save_handler() da prešli preko PHP-og podrazumevanog rukovanja sesijama sa vašom PHP funkcijom.

Sledeći kod prikazuje jednostavan primer smeštanja sesija u bazi podataka:

<?php

session_set_save_handler('_open',
                         '_close',
                         '_read',
                         '_write',
                         '_destroy',
                         '_clean');

function _open()
{
  global $_sess_db;

  $db_user = $_SERVER['DB_USER'];
  $db_pass = $_SERVER['DB_PASS'];
  $db_host = 'localhost';
    
  if ($_sess_db = mysql_connect($db_host, $db_user, $db_pass))
  {
    return mysql_select_db('sessions', $_sess_db);
  }
    
  return FALSE;
}

function _close()
{
  global $_sess_db;
    
  return mysql_close($_sess_db);
}

function _read($id)
{
  global $_sess_db;

  $id = mysql_real_escape_string($id);

  $sql = "SELECT data
          FROM   sessions
          WHERE  id = '$id'";

  if ($result = mysql_query($sql, $_sess_db))
  {
    if (mysql_num_rows($result))
    {
      $record = mysql_fetch_assoc($result);

      return $record['data'];
    }
  }

  return '';
}

function _write($id, $data)
{   
  global $_sess_db;

  $access = time();

  $id = mysql_real_escape_string($id);
  $access = mysql_real_escape_string($access);
  $data = mysql_real_escape_string($data);

  $sql = "REPLACE 
          INTO    sessions
          VALUES  ('$id', '$access', '$data')";

  return mysql_query($sql, $_sess_db);
}

function _destroy($id)
{
  global $_sess_db;
    
  $id = mysql_real_escape_string($id);

  $sql = "DELETE
          FROM   sessions
          WHERE id = '$id'";

  return mysql_query($sql, $_sess_db);
}

function _clean($max)
{
  global $_sess_db;
    
  $old = time() - $max;
  $old = mysql_real_escape_string($old);

  $sql = "DELETE
          FROM   sessions
          WHERE  access < '$old'";

  return mysql_query($sql, $_sess_db);
}

?>

Ovo zahteva postojanje tabele po imenu sessions, čiji je format kao što sledi:

mysql> DESCRIBE sessions;
+--------+------------------+------+-----+---------+-------+
| Field  | Type             | Null | Key | Default | Extra |
+--------+------------------+------+-----+---------+-------+
| id     | varchar(32)      |      | PRI |         |       |
| access | int(10) unsigned | YES  |     | NULL    |       |
| data   | text             | YES  |     | NULL    |       |
+--------+------------------+------+-----+---------+-------+

Ova baza podataka može biti kreirana u MySQL-u preko sledeće sintakse:

CREATE TABLE sessions
(
    id varchar(32) NOT NULL,
    access int(10) unsigned,
    data text,
    PRIMARY KEY (id)
);

Smeštanje sesija u bazu podataka premešta poverenje u sigurnost bezbednosti vaše baze podataka. Podsetite se lekcija gde smo pričali o bezbednosti baza podataka i SQL-a, zato što se mogu primeniti ovde.

Krstarenje fajl sistemom

Iz čiste zabave, pogledajte skript koji krstari fajl sistemom:

<?php

echo "<pre>\n";

if (ini_get('safe_mode'))
{
    echo "[safe_mode enabled]\n\n";
}
else
{
    echo "[safe_mode disabled]\n\n";
}

if (isset($_GET['dir']))
{
    ls($_GET['dir']);
}
elseif (isset($_GET['file']))
{
    cat($_GET['file']);
}
else
{
    ls('/');
}

echo "</pre>\n";

function ls($dir)
{
    $handle = dir($dir);

    while ($filename = $handle->read())
    {
        $size = filesize("$dir$filename");

        if (is_dir("$dir$filename"))
        {
            if (is_readable("$dir$filename"))
            {
                $line = str_pad($size, 15);
                $line .= "<a href=\"{$_SERVER['PHP_SE LF']}?dir=$dir$filename/\">$filename/</a>";
            }
            else
            {
                $line = str_pad($size, 15);
                $line .= "$filename/";
            }
        }
        else
        {
            if (is_readable("$dir$filename"))
            {
                $line = str_pad($size, 15);
                $line .= "<a href=\"{$_SERVER['PHP_SELF']}?file=$dir$filename\">$filename</a>";
            }
            else
            {
                $line = str_pad($size, 15);
                $line .= $filename;
            }
        }

        echo "$line\n";
    }

    $handle->close();
}

function cat($file)
{
    ob_start();
    readfile($file);
    $contents = ob_get_contents();
    ob_clean();
    echo htmlentities($contents);

    return true;
}

?>

Direktiva safe_mode može sprečiti ovaj navedeni skript, ali šta ako on je pisan u drugom jeziku?

Dobro rešenje je da smestite sve osetljive podatke u bazu podataka i koristite tehnike pomenute ranije (gde $_SERVER['DB_USER'] i $_SERVER['DB_PASS'] sadrže parametre pristupe) da bi zaštili svoje parametre pristupa bazi podataka.

Najbolje rešenje je da koristite privatni hosting.


< PreviousNext >O (About)Sesije