Nerijus Kislauskas rašė:
> On 03/23/2012 11:42 AM, Laimis wrote:
>> Reikia skaityti ir nagrinėti.
>
> Na, paskaičiau, pasinagrinėjau ir mano apibendrinimas būtų toks:
>
> allow_url_include (priklausantis nuo allow_url_fopen) yra mechanizmas
> reguliuoti funkcijų include(), include_once(), require(), require_once()
> veikimą. Jei nori includinti/requirinti iš URL, turi dar suhosin
> blacklist/whitelist mechanizmą kaip apsaugą.
Iš tikrųjų yra taip:
include/require kviečia (trasa):
zend_stream_open() ...->
php_stream_open_for_zend() ->
php_stream_open_for_zend_ex() ->
php_stream_open_wrapper() ==
_php_stream_open_wrapper_ex() ->
php_stream_locate_url_wrapper()
Tuo tarpu fopen() ir kt. funkcijos atbėga iki
php_stream_locate_url_wrapper() savarankiškai (ne per zend_stream_open())
Būtent php_stream_locate_url_wrapper() (streams.c) funkcijoje ir yra
tikrinama allow_url_fopen bei allow_url_include:
if (wrapperpp && (*wrapperpp)->is_url &&
(options & STREAM_DISABLE_URL_PROTECTION) == 0 &&
(!PG(allow_url_fopen) ||
(((options & STREAM_OPEN_FOR_INCLUDE) ||
PG(in_user_include)) && !PG(allow_url_include)))) {
if (options & REPORT_ERRORS) {
/* protocol[n] probably isn't '\0' */
char *protocol_dup = estrndup(protocol, n);
if (!PG(allow_url_fopen)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s:// wrapper is
disabled in the server configuration by allow_url_fopen=0", protocol_dup);
} else {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s:// wrapper is
disabled in the server configuration by allow_url_include=0", protocol_dup);
}
efree(protocol_dup);
}
return NULL;
}
suhosin'as įsiterpia į zend_stream_open() todėl include/require galioja
papildoma apsauga, tačiau tai neįtakoja
fopen() ir kt. funkcijų, kurios kviečia php_stream_locate_url_wrapper().
Išeitis yra pasiredaguoti pačiam streams.c arba, — turbūt būtų
paprasčiau, — pasinaudoti jau minėto suhosin'o tėvo Hardening-Patch:
http://www.hardened-php.net/hardening_patch.14.html
funkcija php_is_valid_include() (ir susijusiu kodu), kuri realizuoja
whitelist'ą/blacklist'ą ir kuri būtų kviečiama iš
php_stream_locate_url_wrapper().
Gal kiek bjauresnė užduotis/problema — atsirankioti susijusį kodą iš
įvairių patch'intų failų/vietų, tačiau neturėtų būti labai sunku.
Kita vertus, dar paprasčiau būtų modifikuoti patį suhosin'ą (kartu su
php:streams.c) ir pasinaudoti execute.c:suhosin_check_filename(), kuri
būtų kviečiama iš php_stream_locate_url_wrapper().
> Kažkaip sunku patikėti, kad PHP kūrėjai nepagalvojo, kad fopen() gali
> naudotis tiek geriečiai, tiek blogiečiai, ir kad administratoriams yra
> būtinybė skirstyti URL į gerus ir blogus. Suhosin bent jau galėjo apie
> tai pagalvoti.
Tai tada PHP kūrėjai „nepagalvojo“, kad bet kokia tinklinė komunikacija
yra blogis...
Ar pakiši cutom url'ą fopen(), ar ip socket'ui, ar bet kokiai kitai
tinklinei funkcijai. Uždrausti viską?
fopen() juk gauna duomenis ir pagal visą gerąją (saugumo ir apskritai)
praktiką yra kvaila ir/ar griežtai nerekomenduojama to turinio
interpretuoti kaip kodo (eval). Suhosin apie tai pagalvojo, nes įvedė
apsaugą (na, whitelist'us/blacklist'us, nes pagal viską turbūt daugumoje
konfigūracijų allow_url_fopen/allow_url_include = 0) include/require su
ta mintim, kad gali egzistuoti patikimi host'ai, iš kurių būtų galima
include'inti. Tačiau tai blankiai galioja fopen() ir alike, nes tuomet
balcklist'us/whitelist'us reikėtų iš esmės kurti visoms tinklinėms
komunikacijoms.