Защита на сесии

pro12

Registered
Има ли списъл от защита на сесиите от кражба? Тази функция session_regenerate_id Разбрах, че изтрива старите фаилове на сесиите и създава нови при обновяване на сесиите. Може да се направи защита по ип но няма да е одачно според мен. Ако направя сесиите с отпечатък на браузера може 1000 човека да използват един и същ браузер. Каква защита е подходяща за сесии? Аз си бях измислил защита, но като четох за сесиите ми се стори, че незащитава нищо. Се пак ще споделя моята идея за защита. При логин генерирам код и после го проверявам дали съвпада с този потребител.
 
Хубаво е да правиш отпечатък на браузъра и не само. Също гледай от коя държава и от кой град е ип-то. Също операционна система. Това не е 100% гаранция за сигурност, но все пак е още едно ниво на защита. Когато си дал на потребител права да трие или да качва нещо в базата, някой хакер може да се опита да се възползва от това. Да кажем че е откраднал сесията на даден потребител, и опитва да изтрие нещо от базата. Ти трябва да си се погрижил при такова действие(демек триене, качване и др.) да правиш допълнителна проверка която е невидима за потребителя. Един вид сравняваш отпечатъка който си направил. Ако нещо не съвпада на сто процента(браузър+версия, операционна система, държава, град) не позволяваш да се изпълни заявката. Отпечатъкът трябва да се записва в момента на създаване на сесията. Един вид нова сесия нов отпечатък, валиден докато е валидна сесията.
 
Това, което си измислил е достатъчно добро.
@terroristd - той иска да направи същото, само че с random string, вместо отпечатък + ip + ...
Даже ще е хубаво на всеки request да проверяваш дали този стринг в БД и в сесията съвпадат.
 
teroristd каза:
... Ако нещо не съвпада на сто процента(браузър+версия, операционна система, държава, град) не позволяваш да се изпълни заявката...
В този случай не само не позволяваш да се изпълни заявката, а направо правиш session_destroy(); и извеждаш съответната страница за нелогнати юзери.
 
lam3r4370 каза:
Това, което си измислил е достатъчно добро.
@terroristd - той иска да направи същото, само че с random string, вместо отпечатък + ip + ...
Даже ще е хубаво на всеки request да проверяваш дали този стринг в БД и в сесията съвпадат.

Рандом стринг и отпечатък са две различни работи. Нищо не пречи да ги направи и двете.
 
teroristd каза:
lam3r4370 каза:
Това, което си измислил е достатъчно добро.
@terroristd - той иска да направи същото, само че с random string, вместо отпечатък + ip + ...
Даже ще е хубаво на всеки request да проверяваш дали този стринг в БД и в сесията съвпадат.

Рандом стринг и отпечатък са две различни работи. Нищо не пречи да ги направи и двете.

Аз не казвам, че не са, просто няма смисъл да прави и двете. Защо ти е отпечатък, с който проверяваш за session hijacking, като можеш да използваш просто един рандом стринг за същата цел?
 
teroristd каза:
Обясни по точно как ще те предпази този стринг?
Както те предпазва отпечатъка :)
Нали идеята на отпечатъка е да е уникален, за да се разбере дали потребителят не е логнат от друго място, и съответно, ако е логнат, предната сесият да се премахне. Рандом стринга върши същата работа, даже е по-лесон да се генерира, отколкото да правиш отпечатък + ip + ...
 
Поправи ме ако греша. Когато някой се логне създаваш рандом стринг който отговаря на сесията. Някой краде тази сесия и автоматично този стринг важи и за него. Ти не можеш да направиш разлика между двамата, защото нов стринг се създава при нова сесия, а хакера използва текущата. Докато при подписа можеш да направиш сравнение.
 
Така ли трябва да направя отпечатъка на браузера.
PHP:
<?php
session_start();
include"autolog.php";
if (!empty($HTTP_SESSION_VARS['username']) && 
      $_SESSION['HTTP_USER_AGENT'] != md5($_SERVER['HTTP_USER_AGENT'])) 
  {  

echo $HTTP_SESSION_VARS['username'];
  }
  else
  {
	  echo not;
  }
?>
 
teroristd каза:
Поправи ме ако греша. Когато някой се логне създаваш рандом стринг който отговаря на сесията. Някой краде тази сесия и автоматично този стринг важи и за него. Ти не можеш да направиш разлика между двамата, защото нов стринг се създава при нова сесия, а хакера използва текущата. Докато при подписа можеш да направиш сравнение.
Прав си, в рамката на една сесия няма да сработи :?:
 
В повече от една сесия пък съвсем няма да сработи :) . Да кажем че хакера е откраднал парола и юзърнейм. И двамата се логват и ще има две сесии и два стринга които ще си важат. Няма как да разбереш кой е истинският собственик на акаунта. Има го и това че може собственика да е дал на някой приятел името и паролата, за да може да си качва и да си сваля някакви работи. За да може да се направи разлика трябва да е само една сесия и крадеца винаги ще е втори.
 
pro12 каза:
Така ли трябва да направя отпечатъка на браузера.
PHP:
<?php
session_start();
include"autolog.php";
if (!empty($HTTP_SESSION_VARS['username']) && 
      $_SESSION['HTTP_USER_AGENT'] != md5($_SERVER['HTTP_USER_AGENT'])) 
  {  

echo $HTTP_SESSION_VARS['username'];
  }
  else
  {
	  echo not;
  }
?>
Не разбрах дали отпечатъка на браузера както съм го направил защитава нещо?
 
След малко ще ти дам една готова която имам от преди време, че сега имам малко работа.
 
Правиш си един пхп файл да се казва GetIPAddress.php в него слагаш този клас.

Код:
<?php

class GetIPAddress {

    private $_ip = null;
    private $_result = null;
    private $_arrResult = array();
    private $_serverArr = array();
    private $_key = null;
    private $_ipAddress = null;

    public function userInfo() {
        $this->_ip = $this->getServerTypes();
        $this->_result = json_decode(file_get_contents("http://ip-api.com/" . $this->_ip . "/json"));

        if ($this->_result != null) {

            $this->_arrResult = array($this->_result->status, $this->_result->country, $this->_result->countryCode,
                $this->_result->region, $this->_result->regionName, $this->_result->city, $this->_result->zip,
                $this->_result->lat, $this->_result->lon, $this->_result->timezone, $this->_result->isp,
                $this->_result->org, $this->_result->as, $this->_result->query);

            return $this->_arrResult;
        }
    }

    private function getServerTypes() {

        $this->_serverArr = array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP',
            'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR');

        foreach ($this->_serverArr as $this->_key) {

            if (array_key_exists($this->_key, $_SERVER) === true) {

                foreach (explode(',', $_SERVER[$this->_key]) as $this->_ipAddress) {

                    $this->_ipAddress = trim($this->_ipAddress);

                    if (filter_var($this->_ipAddress, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false) {

                        return $this->_ipAddress;
                    }
                }
            }
        }
    }

}

Ето пример как се ползва.

Код:
<?php

            //Инклудваш
            include 'GetIPAddress.php';

            //Създаваш нов обект
            $userInfo = new GetIPAddress();

            //Викаш функцията userInfo() която връща масив
            $result = $userInfo->userInfo();

         
                //Можеш да достъпваш даден елемент от масива
                //В долния пример е града
                //echo $result[5];

                //Можеш да изведеш и целия масив
                foreach ($result as $arr) {
                    echo $arr . '<br>';
            }

            ?>

Ето какво съдържа масива за да се ориентираш кой елемент какво ти показва.

Код:
array (
  'status' => 'success',
  'country' => 'COUNTRY',
  'countryCode' => 'COUNTRY CODE',
  'region' => 'REGION CODE',
  'regionName' => 'REGION NAME',
  'city' => 'CITY',
  'zip' => ZIP CODE,
  'lat' => LATITUDE,
  'lon' => LONGITUDE,
  'timezone' => 'TIME ZONE',
  'isp' => 'ISP NAME',
  'org' => 'ORGANIZATION NAME',
  'as' => 'AS NUMBER / NAME',
  'query' => 'IP ADDRESS USED FOR QUERY',
)

Ти в случая трябва да го викаш в логина и да записваш информацията за дадения потребител в базата. В последствие на ключовите места като изтриване например пак го викаш и сравняваш с това което е в базата.

п.п.
Естествено няма да му даваш echo както в примера :D това е за да го изпробваш. Принципно тука няма код за браузър и операционна система, но това е по-добро.
 
Ето подобрена версия на класа. Добавил съм код за браузър и операционна система. Ползва се по същия начин както в примера от горния пост. Копи пейст и си готов.

Код:
<?php

class GetIPAddress {

    private $_ip = null;
    private $_result = null;
    private $_arrResult = array();
    private $_serverArr = array();
    private $_key = null;
    private $_ipAddress = null;
    private $_userAgent = null;
    private $_osPlatform = null;
    private $_osArr = array();
    private $_browser = null;

    public function __construct() {
        $this->_userAgent = $_SERVER['HTTP_USER_AGENT'];
    }

    public function userInfo() {
        $this->_ip = $this->getServerTypes();
        $this->_result = json_decode(file_get_contents("http://ip-api.com/" . $this->_ip . "/json"));
        $this->getOS();
        $this->_browser = $this->getBrowser($this->_userAgent);

        if ($this->_result != null) {

            $this->_arrResult = array($this->_result->status, $this->_result->country, $this->_result->countryCode,
                $this->_result->region, $this->_result->regionName, $this->_result->city, $this->_result->zip,
                $this->_result->lat, $this->_result->lon, $this->_result->timezone, $this->_result->isp,
                $this->_result->org, $this->_result->as, $this->_result->query, $this->_osPlatform, $this->_browser);

            return $this->_arrResult;
        }
    }

    private function getServerTypes() {

        $this->_serverArr = array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP',
            'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR');

        foreach ($this->_serverArr as $this->_key) {

            if (array_key_exists($this->_key, $_SERVER) === true) {

                foreach (explode(',', $_SERVER[$this->_key]) as $this->_ipAddress) {

                    $this->_ipAddress = trim($this->_ipAddress);

                    if (filter_var($this->_ipAddress, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false) {

                        return $this->_ipAddress;
                    }
                }
            }
        }
    }

    private function getOS() {

        $this->_osPlatform = 'Unknown OS Platform';

        $this->_osArr = array(
            '/windows nt 10/i' => 'Windows 10',
            '/windows nt 6.3/i' => 'Windows 8.1',
            '/windows nt 6.2/i' => 'Windows 8',
            '/windows nt 6.1/i' => 'Windows 7',
            '/windows nt 6.0/i' => 'Windows Vista',
            '/windows nt 5.2/i' => 'Windows Server 2003/XP x64',
            '/windows nt 5.1/i' => 'Windows XP',
            '/windows xp/i' => 'Windows XP',
            '/windows nt 5.0/i' => 'Windows 2000',
            '/windows me/i' => 'Windows ME',
            '/win98/i' => 'Windows 98',
            '/win95/i' => 'Windows 95',
            '/win16/i' => 'Windows 3.11',
            '/macintosh|mac os x/i' => 'Mac OS X',
            '/mac_powerpc/i' => 'Mac OS 9',
            '/linux/i' => 'Linux',
            '/ubuntu/i' => 'Ubuntu',
            '/iphone/i' => 'iPhone',
            '/ipod/i' => 'iPod',
            '/ipad/i' => 'iPad',
            '/android/i' => 'Android',
            '/blackberry/i' => 'BlackBerry',
            '/webos/i' => 'Mobile'
        );


        foreach ($this->_osArr as $key => $val) {
            if (preg_match($key, $this->_userAgent)) {
                $this->_osPlatform = $val;
            }
        }

        return $this->_osPlatform;
    }

    private function getBrowser($useragent) {
        // check for most popular browsers first
        // unfortunately, that's IE. We also ignore Opera and Netscape 8
        // because they sometimes send msie agent
        if (strpos($useragent, 'MSIE') !== FALSE && strpos($useragent, 'Opera') === FALSE && strpos($useragent, 'Netscape') === FALSE) {
            //deal with Blazer
            if (preg_match("/Blazer\/([0-9]{1}\.[0-9]{1}(\.[0-9])?)/", $useragent, $matches)) {
                return 'Blazer ' . $matches[1];
            }
            //deal with IE
            if (preg_match("/MSIE ([0-9]{1,2}\.[0-9]{1,2})/", $useragent, $matches)) {
                return 'Internet Explorer ' . $matches[1];
            }
        } elseif (strpos($useragent, 'IEMobile') !== FALSE) {
            if (preg_match("/IEMobile\/([0-9]{1,2}\.[0-9]{1,2})/", $useragent, $matches)) {
                return 'Internet Explorer Mobile ' . $matches[1];
            }
        } elseif (strpos($useragent, 'Gecko')) {
            //deal with Gecko based
            //if firefox
            if (preg_match("/Firefox\/([0-9]{1,2}\.[0-9]{1,2}(\.[0-9]{1,2})?)/", $useragent, $matches)) {
                return 'Mozilla Firefox ' . $matches[1];
            }

            //if Netscape (based on gecko)
            if (preg_match("/Netscape\/([0-9]{1}\.[0-9]{1}(\.[0-9])?)/", $useragent, $matches)) {
                return 'Netscape ' . $matches[1];
            }

            //check chrome before safari because chrome agent contains both
            if (preg_match("/Chrome\/([^\s]+)/", $useragent, $matches)) {
                return 'Google Chrome ' . $matches[1];
            }

            //if Safari (based on gecko)
            if (preg_match("/Safari\/([0-9]{2,3}(\.[0-9])?)/", $useragent, $matches)) {
                return 'Safari ' . $matches[1];
            }

            //if Galeon (based on gecko)
            if (preg_match("/Galeon\/([0-9]{1}\.[0-9]{1}(\.[0-9])?)/", $useragent, $matches)) {
                return 'Galeon ' . $matches[1];
            }

            //if Konqueror (based on gecko)
            if (preg_match("/Konqueror\/([0-9]{1}\.[0-9]{1}(\.[0-9])?)/", $useragent, $matches)) {
                return 'Konqueror ' . $matches[1];
            }

            // if Fennec (based on gecko)
            if (preg_match("/Fennec\/([0-9]{1}\.[0-9]{1}(\.[0-9])?)/", $useragent, $matches)) {
                return 'Fennec' . $matches[1];
            }

            // if Maemo (based on gecko)
            if (preg_match("/Maemo\/([0-9]{1}\.[0-9]{1}(\.[0-9])?)/", $useragent, $matches)) {
                return 'Maemo' . $matches[1];
            }

            //no specific Gecko found
            //return generic Gecko
            return 'Gecko based';
        } elseif (strpos($useragent, 'Opera') !== FALSE) {
            //deal with Opera
            if (preg_match("/Opera[\/ ]([0-9]{1}\.[0-9]{1}([0-9])?)/", $useragent, $matches)) {
                return 'Opera ' . $matches[1];
            }
        } elseif (strpos($useragent, 'Lynx') !== FALSE) {
            //deal with Lynx
            if (preg_match("/Lynx\/([0-9]{1}\.[0-9]{1}(\.[0-9])?)/", $useragent, $matches)) {
                return 'Lynx ' . $matches[1];
            }
        } elseif (strpos($useragent, 'Netscape') !== FALSE) {
            //NN8 with IE string
            if (preg_match("/Netscape\/([0-9]{1}\.[0-9]{1}(\.[0-9])?)/", $useragent, $matches)) {
                return 'Netscape ' . $matches[1];
            }
        } else {
            //unrecognized, this should be less than 1% of browsers (not counting bots like google etc)!
            return 'unknown';
        }
    }

}
 
teroristd каза:
Правиш си един пхп файл да се казва GetIPAddress.php в него слагаш този клас.

Код:
<?php

class GetIPAddress {

    private $_ip = null;
    private $_result = null;
    private $_arrResult = array();
    private $_serverArr = array();
    private $_key = null;
    private $_ipAddress = null;

    public function userInfo() {
        $this->_ip = $this->getServerTypes();
        $this->_result = json_decode(file_get_contents("http://ip-api.com/" . $this->_ip . "/json"));

        if ($this->_result != null) {

            $this->_arrResult = array($this->_result->status, $this->_result->country, $this->_result->countryCode,
                $this->_result->region, $this->_result->regionName, $this->_result->city, $this->_result->zip,
                $this->_result->lat, $this->_result->lon, $this->_result->timezone, $this->_result->isp,
                $this->_result->org, $this->_result->as, $this->_result->query);

            return $this->_arrResult;
        }
    }

    private function getServerTypes() {

        $this->_serverArr = array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP',
            'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR');

        foreach ($this->_serverArr as $this->_key) {

            if (array_key_exists($this->_key, $_SERVER) === true) {

                foreach (explode(',', $_SERVER[$this->_key]) as $this->_ipAddress) {

                    $this->_ipAddress = trim($this->_ipAddress);

                    if (filter_var($this->_ipAddress, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false) {

                        return $this->_ipAddress;
                    }
                }
            }
        }
    }

}

Ето пример как се ползва.

Код:
<?php

            //Инклудваш
            include 'GetIPAddress.php';

            //Създаваш нов обект
            $userInfo = new GetIPAddress();

            //Викаш функцията userInfo() която връща масив
            $result = $userInfo->userInfo();

         
                //Можеш да достъпваш даден елемент от масива
                //В долния пример е града
                //echo $result[5];

                //Можеш да изведеш и целия масив
                foreach ($result as $arr) {
                    echo $arr . '<br>';
            }

            ?>

Ето какво съдържа масива за да се ориентираш кой елемент какво ти показва.

Код:
array (
  'status' => 'success',
  'country' => 'COUNTRY',
  'countryCode' => 'COUNTRY CODE',
  'region' => 'REGION CODE',
  'regionName' => 'REGION NAME',
  'city' => 'CITY',
  'zip' => ZIP CODE,
  'lat' => LATITUDE,
  'lon' => LONGITUDE,
  'timezone' => 'TIME ZONE',
  'isp' => 'ISP NAME',
  'org' => 'ORGANIZATION NAME',
  'as' => 'AS NUMBER / NAME',
  'query' => 'IP ADDRESS USED FOR QUERY',
)

Ти в случая трябва да го викаш в логина и да записваш информацията за дадения потребител в базата. В последствие на ключовите места като изтриване например пак го викаш и сравняваш с това което е в базата.

п.п.
Естествено няма да му даваш echo както в примера :D това е за да го изпробваш. Принципно тука няма код за браузър и операционна система, но това е по-добро.
Направих всичко както ми каза. Но не извежда нишо бяла страница само.
 
Някъде грешиш, опиши какво точно и как направи? Още едно уточнение трябва да имаш интернет за да работи, но щом пишеш тук значи не е там проблема.
 

Back
Горе