Sep 09

Позавчера обратился ко мне один из заказчиков с проблемкой…

Проблема заключалась в следующем - после переноса всех скриптов и бд с одного хостинга на другой возникла проблема - не открывались страницы, отличные от главной. После просмотра кода (код, кстати, ужасный) - догадался в чем проблема - на старом хостинге в PHP флаг register_globals был включен, в новом - выключен, поэтому код типа:

if($id > 0)  {
    // загружаем страничку, соответствующую данному id
} else {
    // загружаем index
}

совсем не работал (переменной $id в глобальном пространстве имен не было). Через пару минут в голову пришло решение - эмулировать работу флага register_globals. Где-то я уже видел такое решение, кажется в Joomla’е, но искать времени особо не было.

В итоге получилось следующее решение:

function register_globals_array($array)
{
    foreach($array as $key => $value)
        if(preg_match("/[a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*/", $key))
            $GLOBALS[$key] = $value;
}

function register_globals()
{
    register_globals_array($_GET);
    register_globals_array($_POST);
    register_globals_array($_COOKIE);
    register_globals_array($_ENV);
    register_globals_array($_SERVER);
}

Пользуйтесь на здоровье.

PS. Да… Ну почему бОльшая часть кода на PHP написана так херово… :(

written by fxposter \\ tags:


28 Responses to “Эмуляция register_globals”

  1. 1. DM Says:

    extract($_GET);
    extract($_POST);
    extract($_COOKIE);
    extract($_ENV);
    extract($_SERVER);

    Ы?

  2. 2. FX Poster Says:

    ммм :) не знал, спасибо.

  3. 3. DM Says:

    Я когда-то возмущался почему вот описано так, а на сервере не работает. Нашел и сделал этот хак. А через месяц таки прочел главу Security в мануале, почесал в затылке, и заменил на обращения к $_*.

  4. 4. FX Poster Says:

    Да там просто система такая, что лучше переписать, что, собственно, сейчас и планируется. А пока что – пусть так живет. :)

  5. 5. Kallisto Says:

    Давно ушел с вариантом extract, потому как он когда-то конченый админ в целях безопасности (???) отключил эту функцию.

    С тех времен все конфиг файлы у меня начинаются со строк:
    foreach($_GET as $key=>$value) $$key=$value;
    foreach($_POST as $key=>$value) $$key=$value;

    и все довольны ;)

  6. 6. FX Poster Says:

    А если в QUERY_STRING будет “1=1” у тебя будет ошибка. Я ж не из головы regexp взял ;)

  7. 7. Kallisto Says:

    Какая ошибка? Нет никакой ошибки.

    Другой вопрос доступа к таким переменным будет доступно только через $_GET (в независимости от опции регистерс_глобалс) или если создавать переменные с заданым префиксом.. это решает extract или если модернизировать чуть-чуть мой код выше.

  8. 8. FX Poster Says:

    Мдя. Мне вот интересно, и как оно интерпретирует вот такую штуку.

    array['1'] = '1';
    foreach($array as $key=>$value) $$key=$value;

    Ошибок не выдает, хотя должно… Мдя. Не нравится мне пхп. Ох, как не нравится.

  9. 9. Kupuyc Says:

    А что, это по русски: эмулировать дыру в безопасности :).

  10. 10. FX Poster Says:

    Ну, в данном случае там ни о какой безопасности речи вообще не шло :)

  11. 11. Kupuyc Says:

    Видимо такая задача ставилась изначально и сразу :)

  12. 12. FX Poster Says:

    Задача ставилась: “сделай так, чтобы оно хотя бы работало. Все равно все переделывать прийдется”.

  13. 13. Kallisto Says:

    При правильной обработке переменных никакой дыры это не создает..;)

  14. 14. Kupuyc Says:

    Не создает? С этого места подробнее, плиз.

  15. 15. Kallisto Says:

    Что именно?

  16. 16. Kupuyc Says:

    Подробнее о мысли выдвигаемой в тезисе “При правильной обработке переменных никакой дыры это не создает..;)”.

  17. 17. FX Poster Says:

    А что тут непонятного? Если register_globals включена, то это не означает, что у тебя автоматически будут проблемы с безопасностью. Если код написан нормально, проверки где нужно стоят – все будет ок, никаких проблем не будет.

    Кстати, обратное тоже верно – если register_globals == off, то это не значит, что твой сайт не хакнут ;)

  18. 18. Kupuyc Says:

    Я почему-то так и думал, что мысль будет из разряда максимально абстрактных :). Я вот о чем: включение опции позволяет злоумышленнику писать в глобальный контекст. Это же катастрофа. Особенно для сложных проектов которые создавались из расчета разграничения контекстов (к слову, эмуляция namespaces статическими свойствами класса позволяет беспокоиться меньше). Не будете же вы проверять переменную цикла в какой-то функции на предмет ее безопасности? (вопрос целесообразности подмены такой важной переменной оставим ввиду академичности примера :))

  19. 19. FX Poster Says:

    2 правила программирования, которые ты рано или поздно поймешь, программируя на пхп:

    1. локальные переменные обязаны быть проинициализированы.
    2. входные данные нужно фильтровать.

    2 правила – и накакие register_globals тебе не страшны.

  20. 20. Kallisto Says:

    Если у тебя 1й выполняемый скрипт начинается с таких строк:
    $value) $$key=$value;
    foreach($_POST as $key=>$value) $$key=$value;
    if(!isset($a)) $a=”;
    if($a==’add_news’)
    {
    … // add news
    }
    if($a==’view’)
    {

    }


    то тут как ни крути регистерс не влияет …

  21. 21. Kup Says:

    Ех… хозяину блога, imho, следует обратиться с этим полным апломба (может и заслуженного, не знаю. Поправьте, если я что-то путаю) советом ко всем “кто в этом чате” – http://www.google.com/search?as_q=register_globals&hl=ru&num=10&btnG=%D0%9F%D0%BE%D0%B8%D1%81%D0%BA+%D0%B2+Google&as_epq=&as_oq=vulnerability+%D1%83%D1%8F%D0%B7%D0%B2%D0%B8%D0%BC%D0%BE%D1%81%D1%82%D1%8C&as_eq=&lr=&as_ft=i&as_filetype=&as_qdr=all&as_occt=any&as_dt=i&as_sitesearch=&as_rights=&safe=images
    Возможно это облегчит жизнь многим, не столь молодым, людям. Грустно слышать…

    Господа, я вижу к чему идет разговор. Давайте так, если мы спорим ради спора, то тогда вы правы, можно даже два раза.

  22. 22. Kallisto Says:

    Причем тут спорим или не спорим.

    Суть в том, что в независимости от параметра регистер_глобалс если проверять переменные на существование и обрабатывать ее согласно нашей цели, то никаким образом значение офф или он на безопасность скрипта не влияет.

  23. 23. Kup Says:

    Это верно, да. С маленьким уточнением – инициализация в текущем контексте (как отмечено FX Poster выше) и проверка в контексте использования. Однако есть одно НО и существенное – это все де юре, де факто же имеем то, что имеем (см. гуглолинк выше). Не так разве? Вот например, как часто Вы проверяете контент куки-переменных? Моя практика показывает, что подавляющее большинство кодеров им безоговорочно доверяет, хотя скурпулезно валидируют GET и POST данные.

  24. 24. Kallisto Says:

    Конченные кодеры значит.. я таких кодеров называю криворукие… ибо так и есть.

    Абсолютно все проверяю… вот приведу функцию которая отвечает пользователь в системе или нет:

    код кривоват немного потому как писался быстро. но работает причем отлично.
    Суть в том, что в куках 2 переменные, юзернейм и пасс.
    .. дальше я думаю понятно:

    function username()
    	{
    		global $config;
    		if(!isset($_COOKIE["username"])) return 0;
    		if(!isset($_COOKIE["passhash"])) return 0;
    		if(strlen($_COOKIE["passhash"])!=32) return 0;
    		$_COOKIE["username"] = str_replace("\\", "", $_COOKIE["username"]);
    		$_COOKIE["username"] = str_replace("\"", "", $_COOKIE["username"]);
    		$_COOKIE["username"] = str_replace(" ", "", $_COOKIE["username"]);
    		$_COOKIE["username"] = str_replace("%", "", $_COOKIE["username"]);
    		$_COOKIE["username"] = str_replace("|", "", $_COOKIE["username"]);
    		$_COOKIE["username"] = str_replace("'", "", $_COOKIE["username"]);
    		$_COOKIE["username"] = str_replace("`", "", $_COOKIE["username"]);
    		$_COOKIE["username"] = str_replace("~", "", $_COOKIE["username"]);
    		$_COOKIE["passhash"] = str_replace("\\", "", $_COOKIE["passhash"]);
    		$_COOKIE["passhash"] = str_replace("\"", "", $_COOKIE["passhash"]);
    		$_COOKIE["passhash"] = str_replace(" ", "", $_COOKIE["passhash"]);
    		$_COOKIE["passhash"] = str_replace("%", "", $_COOKIE["passhash"]);
    		$_COOKIE["passhash"] = str_replace("|", "", $_COOKIE["passhash"]);
    		$_COOKIE["passhash"] = str_replace("'", "", $_COOKIE["passhash"]);
    		$_COOKIE["passhash"] = str_replace("`", "", $_COOKIE["passhash"]);
    		$_COOKIE["passhash"] = str_replace("~", "", $_COOKIE["passhash"]);
    		$user = table("users");
    		$a = mysql_query("select * from $user where p_name='{$_COOKIE["username"]}'") or die(mysql_error()) ;
    		if(mysql_num_rows($a)==0)	return 0;
    		$a = mysql_fetch_assoc($a);
    		$a = $a["p_pass"];
    		if($a!=$_COOKIE["passhash"])
    			{
    				@setcookie("username", "", time()-60*60*24*366);
    				@setcookie("passhash", "", time()-60*60*24*366);
    				return 0;
    			}
    			else
    			{
    				return $_COOKIE["username"];
    			}
    	}

  25. 25. Kallisto Says:

    некороые вырезки можно опустить… но какова цель была уже не помню… код был написан эдак 2004го года.. с тех пор использую его + модификацию и никаких проблем с данными из кук не будет.

    Короче думаю дискуссию можно прекратить и сойтись на том, что в независимости от значения регистерс если кодер криворукий – его не спасет ничего.)

  26. 26. geroy Says:

    появляется много вопросов – а зачем, а почему.. но понять можно – времени было мало (3 года).

    типа если кто из умных увидит косяки – сразу 5 раз повторил: всё было сделано в темпе и кривоватенько, но зато мегасекьюрно, чёрт возьми!… :)
    очень много ненужного – какие то куски чего-то мегамерзкого разбросаны по бедной функции…

    мне вообще кажется какая-то функция “ниочём” – что он там защищает непонятно :)
    хотя, возможно, где-то здесь таится тайный смысл: $user = table(“users”);
    но он опять же по причине секьюрности код скрыт от глаз простых смертных КРИВЫХ кодеров :(

  27. 27. Kallisto Says:

    проехали.

  28. 28. Kupuyc Says:

    Ultima ratio :). Впрочем не важно, кое-что из беседы было вынесено.

Leave a Reply