Tema: Re: web adminų galvos skausmai
Autorius: Laimis
Data: 2012-03-23 20:51:04
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.