Отмена регистрации глобалов?

У меня проблемы с пониманием этой функции. Я знаю, что такое register_globals и как давно он устарел по сравнению с PHP, но я смотрю на этот код и думаю, что в? ...

<?php
    //Undo register_globals
    function unregister_globals() {
        if (ini_get(register_globals)) {
            $array = array('_REQUEST', '_SESSION', '_SERVER', '_ENV', '_FILES');
            foreach ($array as $value) {
                foreach ($GLOBALS[$value] as $key => $var) {
                    if ($var === $GLOBALS[$key]) {
                        unset($GLOBALS[$key]);
                    }
                }
            }
        }
    }
?>

Часть, в которой я не понимаю, это ...

foreach ($array as $value) {
    foreach ($GLOBALS[$value] as $key => $var) {
        if ($var === $GLOBALS[$key]) {
            unset($GLOBALS[$key]);
         }
     }
 }

Этот цикл foreach циклически перебирает каждое значение в массиве $, который мы определили, а затем внутренний цикл foreach захватывает суперглобальный массив из GLOBALS, будь то _REQUEST, _SESSION, _SERVER, _ENV, _FILES и т. Д. проверка того, совпадает ли $ var с ГЛОБАЛЬНОЙ переменной или нет. Если так, то мы его отключим.

Но у меня все еще большие трудности с осознанием этого ...

ОБНОВЛЕНИЕ Вот фрагмент кода, с которым я экспериментирую и отлаживаю. Что произойдет, если register_globals включен, и хакер, ворвавшись, вставит? Auth = 1 в строку запроса? Будет ли auth удален из GLOBALS или он будет повторен?

if( true ) {
    $globals = array(
        '_COOKIE',
        '_GET',
        '_POST',
        '_REQUEST',
        '_SERVE',
        '_SESSION'
    );

    foreach($globals as $global) {
        foreach($GLOBALS[$global] as $k => $v) {
            /* $GLOBALS['_GET'] on the first loop; */
            /* IF WE SAY, $GLOBALS['app_dir'], WE GET THE VALUE */

            if( $v == $GLOBALS[$k] ) {
                echo "K=> " . $k . "<br />";
                echo "V => " . $v . "<br />";
                echo "GLOB => " . $GLOBALS[$k] . "<br />";
            }
        }
    }

            echo $authorized; // a intentional non-defined variable

    //print_r($GLOBALS);
}

Спасибо за ваше время.


person W3Geek    schedule 06.12.2013    source источник
comment
он сбрасывает ВСЕ глобалы, это безумие, не делайте этого   -  person    schedule 07.12.2013
comment
Я проверил свой массив GLOBALS, и все переменные все еще были там после запуска этого внутри моего кода.   -  person W3Geek    schedule 07.12.2013
comment
@ W3Geek var_dump ($ _ GLOBALS) перед запуском и посмотрите, что он содержит   -  person user4035    schedule 07.12.2013
comment
Вы не можете изменить массив внутри цикла foreach, если не передадите итератор по ссылке. Похоже, это предполагается удалить все глобальные объекты, но это не сработает, если вы не foreach ($GLOBALS[$value] as $key => &$var)   -  person EmmyS    schedule 07.12.2013
comment
@ user4035 Я вижу всю свою глобальную информацию? Должен ли я после этого var_dump?   -  person W3Geek    schedule 07.12.2013
comment
@EmmyS Интересно, почему мой код удаляет все значения из массива $ data?   -  person user4035    schedule 07.12.2013
comment
@ W3Geek Итак, этот код вообще не изменяет массив $ _GLOBALS?   -  person user4035    schedule 07.12.2013
comment
@ user4035 - не знаю. Согласно документам, чтобы иметь возможность напрямую изменять Элементы массива внутри цикла предшествуют $ value с помощью &.   -  person EmmyS    schedule 07.12.2013
comment
@ user4035 Да сбрасывает, и $ data становится массивом (0); Хм?   -  person W3Geek    schedule 07.12.2013
comment
@EmmyS Думаю, я нашел причину. В do они используют: foreach ($arr as &$value) - без ключа. Пока снимаем обстановку, пользуемся ключом. Вот почему это работает.   -  person user4035    schedule 07.12.2013
comment
@ user4035 Результаты var_dump: int (1) int (1) int (2) int (2) int (3) int (3) array (0) {}   -  person W3Geek    schedule 07.12.2013
comment
@ user4035 Звучит совершенно нормально? Может быть, потому что вы получаете ссылку, потому что у вас есть ключ?   -  person W3Geek    schedule 07.12.2013


Ответы (3)


Да, этот код выглядит странно:

foreach ($GLOBALS[$value] as $key => $var) {
        if ($var === $GLOBALS[$key]) {//<- ?
            unset($GLOBALS[$key]);
         }
     }

Вы можете имитировать происходящее, используя простой массив, и убедиться, что этот if абсолютно бесполезен:

<?php
$data = array(1,2,3);

foreach ($data as $key => $var) {
    var_dump($var);
    var_dump($data[$key]);
    if ($var === $data[$key]) {
        unset($data[$key]);
    }
}

вывод:

int(1)
int(1)
int(2)
int(2)
int(3)
int(3)

Как видите, значения каждый раз равны, и в итоге $ data будет пустым.

Обновлять

Вот сценарий, который вы можете воспроизвести на своем компьютере:

<?php
extract($_REQUEST);

var_dump($auth);
$array = array('_REQUEST', '_SESSION', '_SERVER', '_ENV', '_FILES');
foreach ($array as $value) {
    if(isset($GLOBALS[$value]))
    {
        foreach ($GLOBALS[$value] as $key => $var) {
            unset($GLOBALS[$key]);
        }
    }
}
var_dump($auth);

Называя это так: http://site/script.php?auth=1

Это дает мне следующий результат:

string(1) "1"
<br />
<b>Notice</b>:  Undefined variable: auth on line 14
NULL

Итак, похоже, что эта переменная auth была уничтожена. Но массив $ GLOBALS по-прежнему содержит много данных.

Обновление 2

Думаю, здесь была наша ошибка:

unset($GLOBALS[$key]);

Почему мы сбрасываем ключ внешнего массива. Если вы сделаете это так:

$array = array('_REQUEST', '_SESSION', '_SERVER', '_ENV', '_FILES');
foreach ($array as $value) {
    if(isset($GLOBALS[$value]))
    {
        foreach ($GLOBALS[$value] as $key => $var) {
            unset($GLOBALS[$value][$key]);
        }
    }
}

Он очистит $ _REQUEST, $ _SESSION и все остальные необходимые массивы.

person user4035    schedule 06.12.2013
comment
Да, но скажем, что у меня есть переменная $ authorized, которую я где-то забыл определить. Хакер может просто прогуляться и добавить? Auth = 1, чтобы установить себе режим бога. Будет ли это отключать $ auth из GLOBALS или? Этот код странный. - person W3Geek; 07.12.2013
comment
@ W3Geek Сейчас пытаюсь провести эксперимент. Сообщу вам в ближайшее время. - person user4035; 07.12.2013
comment
@ W3Geek Думаю, я нашел причину. Посмотрите Обновление 2. - person user4035; 07.12.2013
comment
Мне придется подождать, пока я вернусь домой, чтобы попробовать это. Я сейчас экспериментирую, но у меня нет возможности включить register_globals. Он отключен на моем сервере разработки. Я просто хочу убедиться, что понимаю это. Это так сложно и на нем не так много ресурсов? - person W3Geek; 07.12.2013
comment
@ W3Geek register_globals также отключен на моей машине. Я использовал экстракт ($ _ REQUEST); имитировать register_globals по поведению. stackoverflow.com/questions/16706098 / - person user4035; 07.12.2013
comment
Прохладный! :) Я попробую. Я обновил свой пост выше, указав, что я пытаюсь обернуть в заголовок ... - person W3Geek; 07.12.2013
comment
Мои результаты: VAR_DUMP AUTH BEFORE string (9) 123456789 VAR_DUMP AUTH BEFORE string (9) 123456789 - person W3Geek; 07.12.2013
comment
@ W3Geek Да, этот код вам не поможет, если вы хотите удалить все ненужные глобальные значения. Для этого вы должны определить массив всех допустимых имен глобальных значений и отменить определение всех тех, которые не входят в этот список. - person user4035; 07.12.2013
comment
@ W3Geek Сейчас буду спать, вернусь через 9 часов. - person user4035; 07.12.2013
comment
Я знаю, я просто пытался поэкспериментировать и понять, как это работает. Я ожидал, что $ auth будет NULL; Я вернусь позже. - person W3Geek; 07.12.2013

Глобальные таблицы (особенно $ _GET, $ _POST, $ _COOKIE, $ _ENV, ... и $ GLOBALS-Entries этого суперглобала) изначально заполняются PHP и никогда не должны перезаписываться или удаляться каким-либо приложением.

Любая манипуляция суперглобальными значениями снижает подлинность текущего запроса и работает против преднамеренного поведения PHP.

Вложенный foreach означает, что данный массив будет повторяться (вне foreach), и каждая запись также будет повторяться. Ключ-массив используется как $ key, а значение массива как $ var.

person tr0y    schedule 06.12.2013
comment
Разве вы не отключили бы GLOBAL per-say, если бы я запросил? Auth = 1 в URL-адресе, а в моем коде уже есть переменная $ auth? - person W3Geek; 07.12.2013
comment
нет, я бы не стал, существующие переменные не влияют на $ _GET-Values. Более старые версии PHP допускают поведение, влияющее на безопасность, называемое глобальными регистрами, которое устарело уже несколько десятилетий. В PHP 5.5.x возможно только перезаписать существующие переменные при извлечении () суперглобальных переменных (что соответствует поведению старых регистровых глобальных переменных и, безусловно, является худшей практикой). - person tr0y; 07.12.2013

Теперь, когда я смог увидеть, как это работает на самом деле, я смог осознать это. По сути, если пользователи используют PHP 5.3.0 или ниже и включен 'register_globals', хакеры могут запрашивать общие имена переменных, такие как 'authorized', 'username' и т. Д., Чтобы ввести собственные значения, если переменная уже была определена разработчиком. .

Пример:

if( is_authorized() ) {
    $auth = 1;
}

if( $auth ) {
    // do authorization code here!!!
} else {
    show_login();
}

Вы можете видеть, что $ auth определен условно. Если хакер приходит и пробует что-то вроде index.php? Auth = 1 или index.php? Auth = true, то PHP зарегистрирует это как глобальное значение, оно будет проверено в условном выражении, и наш хакер получит доступ. к приложению.

Я нашел это...

foreach ($array as $value) {
    foreach ($GLOBALS[$value] as $key => $var) {
        if ($var === $GLOBALS[$key]) {
            unset($GLOBALS[$key]);
        }
    }
}

... на самом деле сбрасывает эти значения, и у хакера не будет доступа, однако, как я ранее думал, есть также ошибка. У меня есть два глобальных объекта в моей структуре, называемые $ app_dir и $ sys_dir, указывающие на два важных каталога. Если хакеры придут и скажут что-то вроде index.php? App_dir = application & sys_dir = system, тогда он фактически сбросит эти глобальные переменные из $ GLOBALS. Это создает потенциальную опасность внутри моего фреймворка для всех, кто использует его на PHP 5.3.0 или ниже.

В основном это работает с помощью условных проверок, чтобы увидеть, совпадает ли $ var (наше значение, 'system') с тем же значением, что и внутри $ GLOBAL ['sys_dir']. Кто-нибудь знает, как это исправить?

person W3Geek    schedule 08.12.2013
comment
В этом нет необходимости, если: if ($var === $GLOBALS[$key]). Этот код плохой. - person user4035; 08.12.2013
comment
Дай мне попробовать без него. Разве тогда это не сбило бы с толку? - person W3Geek; 08.12.2013
comment
Да, я показал вам в начале своего ответа, что это то же самое. И поэтому всегда верно. - person user4035; 08.12.2013
comment
Если у вас есть 2 глобальных объекта, указывающих на важные каталоги, они должны быть где-то определены. Когда вы установите для них новые значения, хакерские значения будут потеряны. В чем опасность? - person user4035; 08.12.2013
comment
@ user4035 Подожди, может понадобиться! Ошибка, о которой я упоминал выше, станет еще хуже, если вы удалите условную проверку. Теперь кто-нибудь может запросить index.php? App_dir и sys_dir, и он полностью их отключит. Да, они определены мной, но этот код отключит их, если они будут запрошены, опубликованы и т. Д. - person W3Geek; 08.12.2013
comment
позвольте нам продолжить обсуждение в чате - person W3Geek; 08.12.2013
comment
Нет, извини, сейчас слишком занят. если убрать условную проверку - ничего не произойдет, потому что это условие бесполезно. - person user4035; 08.12.2013
comment
Также не думаю, что эти переменные будут опасны в массивах $ _GET или $ _REQUEST. Если вы используете их как глобальные переменные, значения, хранящиеся в этих массивах, использоваться не будут. - person user4035; 08.12.2013
comment
О, лол, это нормально. Я только что увидел рекомендацию StackOverflow и нажал на нее. : P Но да, это усугубляет ошибку, о которой я упоминал выше, потому что она будет отключаться независимо от того, какое значение запрашивается. Я пробовал это несколько раз, и это ломает мои рамки. - person W3Geek; 08.12.2013