allow_url_fopen / allow_url_include and fine grained control

php.internals

Sara Golemon

19 years ago
allow_url_include has been bashed lately for being "not good enough", and there is a kernel of truth to that, though where the ultimate blame falls if of course a touchy subject. So rather than continue the fight over who's shoulders the job of security should fall on, how about the attached patch which puts a little more power in the hands of the user/site-admin to control what can be treated as a url include, and how it can be treated that way. The short version of the attached patch is this: allow_url_fopen and allow_url_include continue to accept boolean flags in order to behave just as they do now: true/on allows anything, false/off allows only those wrappers without the is_url bit set. In addition, they can be set to a colon delimited list of wrapper names (e.g. allow_url_include=file:compress.bz2:compress.zlib ) When used in this manner, the value of a wrapper's is_url flag is meaningless, only the name is considered. If it's in this list, it's allowed, otherwise not. I've also applied the same concept as was recently added to open_basedir, that is; These settings can be tightened during runtime/perdir context (but not loosened). For example, if the system-wide setting for allow_url_fopen is on, and a given script wants to restrict itself to just local files, they can: ini_set("allow_url_fopen", "file"); Comments welcome, flames not. -Sara Note: I changed the internal names for these settings in order to force 3rd party extensions to review their code if they rely on inspecting those values.

Marcus Börger

19 years ago
Hello Sara, strong +1, awesome work! best regards marcus Wednesday, January 17, 2007, 2:07:15 AM, you wrote:
> Index: main/php_globals.h > =================================================================== > RCS file: /repository/php-src/main/php_globals.h,v > retrieving revision 1.109 > diff -u -p -r1.109 php_globals.h > --- main/php_globals.h 1 Jan 2007 09:29:35 -0000 1.109 > +++ main/php_globals.h 17 Jan 2007 00:55:27 -0000 > @@ -124,7 +124,8 @@ struct _php_core_globals { > zend_bool modules_activated; > zend_bool file_uploads; > zend_bool during_request_startup; > - zend_bool allow_url_fopen; > + char *allow_url_fopen_list; > + char *allow_url_include_list; > zend_bool always_populate_raw_post_data; > zend_bool report_zend_debug; > > @@ -137,7 +138,6 @@ struct _php_core_globals { > > char *disable_functions; > char *disable_classes; > - zend_bool allow_url_include; > #ifdef PHP_WIN32 > zend_bool com_initialized; > #endif > Index: main/main.c > =================================================================== > RCS file: /repository/php-src/main/main.c,v > retrieving revision 1.719 > diff -u -p -r1.719 main.c > --- main/main.c 9 Jan 2007 18:38:38 -0000 1.719 > +++ main/main.c 17 Jan 2007 00:55:27 -0000 > @@ -420,8 +420,8 @@ PHP_INI_BEGIN() > PHP_INI_ENTRY("disable_functions", "", PHP_INI_SYSTEM, NULL) > PHP_INI_ENTRY("disable_classes", "", PHP_INI_SYSTEM, NULL) > > - STD_PHP_INI_BOOLEAN("allow_url_fopen", "1", > PHP_INI_SYSTEM, OnUpdateBool, allow_url_fopen, > php_core_globals, core_globals) > - STD_PHP_INI_BOOLEAN("allow_url_include", "0", > PHP_INI_SYSTEM, OnUpdateBool, allow_url_include, > php_core_globals, core_globals) > + STD_PHP_INI_BOOLEAN("allow_url_fopen", "1", > PHP_INI_ALL, OnUpdateAllowUrl, > allow_url_fopen_list, php_core_globals, core_globals) > + STD_PHP_INI_BOOLEAN("allow_url_include", "0", > PHP_INI_ALL, OnUpdateAllowUrl, > allow_url_include_list, php_core_globals, core_globals) > STD_PHP_INI_BOOLEAN("always_populate_raw_post_data", > "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, > always_populate_raw_post_data, php_core_globals, core_globals) > STD_PHP_INI_ENTRY("realpath_cache_size", "16K", PHP_INI_SYSTEM, > OnUpdateLong, realpath_cache_size_limit, virtual_cwd_globals, cwd_globals) > STD_PHP_INI_ENTRY("realpath_cache_ttl", "120", PHP_INI_SYSTEM, > OnUpdateLong, realpath_cache_ttl, virtual_cwd_globals, cwd_globals) > @@ -1507,6 +1507,12 @@ static void core_globals_dtor(php_core_g > if (core_globals->disable_classes) { > free(core_globals->disable_classes); > } > + if (core_globals->allow_url_fopen_list) { > + free(core_globals->allow_url_fopen_list); > + } > + if (core_globals->allow_url_include_list) { > + free(core_globals->allow_url_include_list); > + } > } > /* }}} */ > > Index: main/php_streams.h > =================================================================== > RCS file: /repository/php-src/main/php_streams.h,v > retrieving revision 1.123 > diff -u -p -r1.123 php_streams.h > --- main/php_streams.h 16 Jan 2007 20:36:04 -0000 1.123 > +++ main/php_streams.h 17 Jan 2007 00:55:27 -0000 > @@ -21,6 +21,8 @@ > #ifndef PHP_STREAMS_H > #define PHP_STREAMS_H > > +#include "php_ini.h" > + > #ifdef HAVE_SYS_TIME_H > #include <sys/time.h> > #endif > @@ -165,7 +167,7 @@ typedef struct _php_stream_wrapper_ops { > struct _php_stream_wrapper { > php_stream_wrapper_ops *wops; /* operations the wrapper can perform */ > void *abstract; /* context for the wrapper */ > - int is_url; /* so > that PG(allow_url_fopen) can be respected */ > + int is_url; /* so > that PG(allow_url_fopen_list)/PG(allow_url_include_list) can be respected */ > > /* support for wrappers to return (multiple) error messages to the stream opener */ > int err_count; > @@ -658,6 +660,11 @@ PHPAPI void php_stream_wrapper_log_error > PHPAPI int _php_stream_make_seekable(php_stream *origstream, php_stream > **newstream, int flags STREAMS_DC TSRMLS_DC); > #define php_stream_make_seekable(origstream, newstream, > flags) _php_stream_make_seekable((origstream), (newstream), (flags) STREAMS_CC TSRMLS_CC) > > +PHP_INI_MH(OnUpdateAllowUrl); > +PHPAPI int php_stream_wrapper_is_allowed(const char *wrapper, int > wrapper_len, const char *setting TSRMLS_DC); > +#define php_stream_allow_url_fopen(wrapper, wrapper_len) > php_stream_wrapper_is_allowed((wrapper), (wrapper_len), PG(allow_url_fopen_list) TSRMLS_CC) > +#define php_stream_allow_url_include(wrapper, wrapper_len) > php_stream_wrapper_is_allowed((wrapper), (wrapper_len), > PG(allow_url_include_list) TSRMLS_CC) > + > /* Give other modules access to the url_stream_wrappers_hash and stream_filters_hash */ > PHPAPI HashTable *_php_stream_get_url_stream_wrappers_hash(TSRMLS_D); > #define php_stream_get_url_stream_wrappers_hash() > _php_stream_get_url_stream_wrappers_hash(TSRMLS_C) > Index: main/streams/streams.c > =================================================================== > RCS file: /repository/php-src/main/streams/streams.c,v > retrieving revision 1.146 > diff -u -p -r1.146 streams.c > --- main/streams/streams.c 16 Jan 2007 20:36:04 -0000 1.146 > +++ main/streams/streams.c 17 Jan 2007 00:55:27 -0000 > @@ -2096,6 +2096,9 @@ PHPAPI php_stream_wrapper *php_stream_lo > } > /* TODO: curl based streams probably support file:// properly */ > if (!protocol || !strncasecmp(protocol, "file", n)) { > + /* fall back on regular file access */ > + php_stream_wrapper *plain_files_wrapper = &php_plain_files_wrapper; > + > if (protocol) { > int localhost = 0; > > @@ -2132,32 +2135,37 @@ PHPAPI php_stream_wrapper *php_stream_lo > return NULL; > } > > + /* The file:// wrapper may have been disabled/overridden */ > if (FG(stream_wrappers)) { > - /* The file:// wrapper may have been disabled/overridden */ > - > - if (wrapperpp) { > - /* It was found so go ahead and provide it */ > - return *wrapperpp; > - } > - > - /* Check again, the original check might have not known the protocol name */ > - if (zend_hash_find(wrapper_hash, "file", > sizeof("file"), (void**)&wrapperpp) == SUCCESS) { > - return *wrapperpp; > + if (!wrapperpp || zend_hash_find(wrapper_hash, > "file", sizeof("file"), (void**)&wrapperpp) == FAILURE) { > + if (options & REPORT_ERRORS) { > + php_error_docref(NULL TSRMLS_CC, > E_WARNING, "Plainfiles wrapper disabled"); > + } > + return NULL; > } > > + /* Handles overridden plain files wrapper */ > + plain_files_wrapper = *wrapperpp; > + } > + > + if (!php_stream_allow_url_fopen("file", sizeof("file") - 1) || > + ((options & STREAM_OPEN_FOR_INCLUDE) && > !php_stream_allow_url_include("file", sizeof("file") - 1)) ) { > if (options & REPORT_ERRORS) { > - php_error_docref(NULL TSRMLS_CC, > E_WARNING, "Plainfiles wrapper disabled"); > + php_error_docref(NULL TSRMLS_CC, > E_WARNING, "file:// wrapper is disabled in the server configuration"); > } > return NULL; > } > - > - /* fall back on regular file access */ > - return &php_plain_files_wrapper; > + > + return plain_files_wrapper; > } > > - if ((wrapperpp && (*wrapperpp)->is_url) && (!PG(allow_url_fopen) > || ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include))) ) { > + if (!php_stream_allow_url_fopen(protocol, n) || > + ((options & STREAM_OPEN_FOR_INCLUDE) && > !php_stream_allow_url_include(protocol, n)) ) { > if (options & REPORT_ERRORS) { > - php_error_docref(NULL TSRMLS_CC, E_WARNING, "URL > file-access is disabled in the server configuration"); > + /* protocol[n] probably isn't '\0' */ > + char *protocol_dup = estrndup(protocol, n); > + php_error_docref(NULL TSRMLS_CC, E_WARNING, > "%s:// wrapper is disabled in the server configuration", protocol_dup); > + efree(protocol_dup); > } > return NULL; > } > @@ -2866,6 +2874,230 @@ PHPAPI int _php_stream_path_decode(php_s > } > /* }}} */ > > +/* {{{ allow_url_fopen / allow_url_include Handlers */ > + > +PHPAPI int php_stream_wrapper_is_allowed(const char *wrapper, int > wrapper_len, const char *setting TSRMLS_DC) > +{ > + int setting_len = setting ? strlen(setting) : 0; > + const char *s = setting, *e = s + setting_len; > + > + if (wrapper_len == (sizeof("zlib") - 1) && strncasecmp("zlib", wrapper, sizeof("zlib") - 1) == 0) { > + wrapper = "compress.zlib"; > + wrapper_len = sizeof("compress.zlib") - 1; > + } > + > + if (!setting || !setting_len) { > + /* NULL or empty indicates that only is_url == 0 wrappers are allowed */ > + HashTable *wrapper_hash = (FG(stream_wrappers) ? > FG(stream_wrappers) : &url_stream_wrappers_hash); > + php_stream_wrapper **wrapperpp; > + char *wrapper_dup; > + > + if (wrapper_len == (sizeof("file") - 1) && > strncasecmp("file", wrapper, sizeof("file") - 1) == 0) { > + /* file:// is non-url */ > + return 1; > + } > + > + wrapper_dup = estrndup(wrapper, wrapper_len); > + php_strtolower(wrapper_dup, wrapper_len); > + if (FAILURE == zend_hash_find(wrapper_hash, wrapper_dup, > wrapper_len + 1, (void**)&wrapperpp)) { > + /* Wrapper not found */ > + efree(wrapper_dup); > + return 0; > + } > + > + if ((*wrapperpp)->is_url) { > + return 0; > + } > + > + /* Wrapper exists and is not is_url */ > + return 1; > + } > + > + if (setting_len == 1 && *setting == '*') { > + /* "*" means everything is allowed */ > + return 1; > + } > + > + /* Otherwise, scan list */ > + while (s < e) { > + const char *p = php_memnstr((char*)s, ":", 1, (char*)e); > + > + if (!p) { > + p = e; > + } > + > + if (wrapper_len == (p - s) && > + strncasecmp(s, wrapper, p - s) == 0) { > + /* wrapper found in list */ > + return 1; > + } > + > + s = p + 1; > + } > + > + return 0; > +} > + > +/* allow_url_*_list accepts: > + * > + * 1/on to enable all URL prefixes > + * 0/off to disable all is_url=1 wrappers > + * A colon delimited list of wrappers to allow (wildcards allowed) > + * e.g. file:gzip:compress.*:php > + */ > +PHP_INI_MH(OnUpdateAllowUrl) > +{ > +#ifndef ZTS > + char *base = (char *) mh_arg2; > +#else > + char *base = (char *) ts_resource(*((int *) mh_arg2)); > +#endif > + char **allow = (char **) (base+(size_t) mh_arg1); > + > + /* BC Enable */ > + if ((new_value_length == 1 && *new_value == '1') || > + (new_value_length == (sizeof("on") - 1) && > strncasecmp(new_value, "on", sizeof("on") - 1) == 0) ) { > + > + if (*allow && strcmp(*allow, "*") == 0) { > + /* Turning on, but that's no change from current, so leave it alone */ > + return SUCCESS; > + } > + > + if (stage != PHP_INI_STAGE_STARTUP) { > + /* Not already on, and not in SYSTEM context, fail */ > + return FAILURE; > + } > + > + /* Otherwise, turn on setting */ > + if (*allow) { > + free(*allow); > + } > + > + *allow = zend_strndup("*", 1); > + > + return SUCCESS; > + } > + > + /* BC disable */ > + if ((new_value_length == 1 && *new_value == '0') || > + (new_value_length == (sizeof("off") - 1) && > strncasecmp(new_value, "off", sizeof("off") - 1) == 0) ) { > + > + /* Always permit shutting off allowurl settings */ > + if (*allow) { > + free(*allow); > + } > + *allow = NULL; > + > + return SUCCESS; > + } > + > + /* Specify as list */ > + if (stage == PHP_INI_STAGE_STARTUP) { > + /* Always allow new settings in startup stage */ > + if (*allow) { > + free(*allow); > + } > + *allow = zend_strndup(new_value, new_value_length); > + > + return SUCCESS; > + } > + > + /* In PERDIR/RUNTIME context, do more work to ensure we're only tightening the restriction */ > + > + if (*allow && strcmp(*allow, "*") == 0) { > + /* Currently allowing everying, so whatever we set it to will be more restrictive */ > + free(*allow); > + *allow = zend_strndup(new_value, new_value_length); > + > + return SUCCESS; > + } > + > + if (!*allow) { > + /* Currently allowing anything with is_url == 0 > + * So long as this list doesn't contain any is_url == 1, allow it > + */ > + HashTable *wrapper_hash = (FG(stream_wrappers) ? > FG(stream_wrappers) : &url_stream_wrappers_hash); > + char *s = new_value, *e = new_value + new_value_length; > + > + while (s < e) { > + php_stream_wrapper **wrapper; > + char *p = php_memnstr(s, ":", 1, e); > + char *scan; > + int scan_len; > + > + if (!p) { > + p = e; > + } > + > + /* file:// is never a URL */ > + if ( (p - s) == (sizeof("file") - 1) && > strncasecmp(s, "file", sizeof("file") - 1) == 0 ) { > + /* file is not a URL */ > + s = p + 1; > + continue; > + } > + > + if ( (p - s) == (sizeof("zlib") - 1) && > strncasecmp(s, "zlib", sizeof("zlib") - 1) == 0 ) { > + /* Wastful since we know that > compress.zlib is already lower cased, but forgivable */ > + scan = estrndup("compress.zlib", sizeof("compress.zlib") - 1); > + scan_len = sizeof("compress.zlib") - 1; > + } else { > + scan = estrndup(s, p - s);; > + scan_len = p - s; > + php_strtolower(scan, scan_len); > + } > + > + if (FAILURE == zend_hash_find(wrapper_hash, scan, scan_len + 1, (void**) &wrapper)) { > + /* Unknown wrapper, not allowed in this context */ > + efree(scan); > + return FAILURE; > + } > + efree(scan); > + > + if ((*wrapper)->is_url) { > + /* Disallowed is_url wrapper specified > when trying to escape is_url == 0 context */ > + return FAILURE; > + } > + > + /* Seems alright so far... */ > + s = p+1; > + } > + > + /* All tests passed, allow it */ > + *allow = zend_strndup(new_value, new_value_length); > + > + return SUCCESS; > + } > + > + /* The current allows are restricted to a specific list, > + * Make certain that our new list is a subset of that list > + */ > + { > + char *s = new_value, *e = new_value + new_value_length; > + > + while (s < e) { > + char *p = php_memnstr(s, ":", 1, e); > + > + if (!p) { > + p = e; > + } > + > + if (!php_stream_wrapper_is_allowed(s, p - s, *allow TSRMLS_CC)) { > + /* Current settings don't allow this wrapper, deny */ > + return FAILURE; > + } > + > + s = p + 1; > + } > + > + free(*allow); > + *allow = zend_strndup(new_value, new_value_length); > + > + return SUCCESS; > + } > +} > + > +/* }}} */ > + > /* > * Local variables: > * tab-width: 4 > Index: ext/standard/php_fopen_wrapper.c > =================================================================== > RCS file: /repository/php-src/ext/standard/php_fopen_wrapper.c,v > retrieving revision 1.58 > diff -u -p -r1.58 php_fopen_wrapper.c > --- ext/standard/php_fopen_wrapper.c 1 Jan 2007 09:29:32 -0000 1.58 > +++ ext/standard/php_fopen_wrapper.c 17 Jan 2007 00:55:27 -0000 > @@ -187,7 +187,8 @@ php_stream * php_stream_url_wrap_php(php > } > > if (!strcasecmp(path, "input")) { > - if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) { > + /* Override default behavior for php://input when used as > an include and allow_url_include is being used in BC (off) mode */ > + if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include_list) ) { > if (options & REPORT_ERRORS) { > php_error_docref(NULL TSRMLS_CC, > E_WARNING, "URL file-access is disabled in the server configuration"); > } > @@ -197,7 +198,8 @@ php_stream * php_stream_url_wrap_php(php > } > > if (!strcasecmp(path, "stdin")) { > - if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) { > + /* Override default behavior for php://stdin when used as > an include and allow_url_include is being used in BC (off) mode */ > + if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include_list) ) { > if (options & REPORT_ERRORS) { > php_error_docref(NULL TSRMLS_CC, > E_WARNING, "URL file-access is disabled in the server configuration"); > } > Index: ext/soap/php_xml.c > =================================================================== > RCS file: /repository/php-src/ext/soap/php_xml.c,v > retrieving revision 1.31 > diff -u -p -r1.31 php_xml.c > --- ext/soap/php_xml.c 17 Jan 2007 00:22:48 -0000 1.31 > +++ ext/soap/php_xml.c 17 Jan 2007 00:55:27 -0000 > @@ -80,16 +80,19 @@ xmlDocPtr soap_xmlParseFile(const char * > { > xmlParserCtxtPtr ctxt = NULL; > xmlDocPtr ret; > - zend_bool old_allow_url_fopen; > + char *old_allow_url_fopen_list; > > /* > xmlInitParser(); > */ > > - old_allow_url_fopen = PG(allow_url_fopen); > - zend_alter_ini_entry("allow_url_fopen", > sizeof("allow_url_fopen"), "1", 1, PHP_INI_SYSTEM, PHP_INI_STAGE_RUNTIME); > + old_allow_url_fopen_list = PG(allow_url_fopen_list); > + if (!old_allow_url_fopen_list) { > + old_allow_url_fopen_list = ""; > + } > + zend_alter_ini_entry("allow_url_fopen", > sizeof("allow_url_fopen"), "*", 1, PHP_INI_SYSTEM, PHP_INI_STAGE_RUNTIME); > ctxt = xmlCreateFileParserCtxt(filename); > - zend_alter_ini_entry("allow_url_fopen", > sizeof("allow_url_fopen"), old_allow_url_fopen ? "1" : "0", 1, > PHP_INI_SYSTEM, PHP_INI_STAGE_RUNTIME); > + zend_alter_ini_entry("allow_url_fopen", > sizeof("allow_url_fopen"), old_allow_url_fopen_list, > strlen(old_allow_url_fopen_list), PHP_INI_SYSTEM, PHP_INI_STAGE_RUNTIME); > if (ctxt) { > ctxt->keepBlanks = 0; > ctxt->sax->ignorableWhitespace = soap_ignorableWhitespace; > Index: ext/soap/php_http.c > =================================================================== > RCS file: /repository/php-src/ext/soap/php_http.c,v > retrieving revision 1.100 > diff -u -p -r1.100 php_http.c > --- ext/soap/php_http.c 17 Jan 2007 00:22:48 -0000 1.100 > +++ ext/soap/php_http.c 17 Jan 2007 00:55:27 -0000 > @@ -232,7 +232,7 @@ int make_http_soap_request(zval *this_p > int content_type_xml = 0; > char *content_encoding; > char *http_msg = NULL; > - zend_bool old_allow_url_fopen; > + char *old_allow_url_fopen_list; > soap_client_object *client; > > if (this_ptr == NULL || Z_TYPE_P(this_ptr) != IS_OBJECT) { > @@ -317,13 +317,16 @@ try_again: > return FALSE; > } > > - old_allow_url_fopen = PG(allow_url_fopen); > - zend_alter_ini_entry("allow_url_fopen", > sizeof("allow_url_fopen"), "1", 1, PHP_INI_SYSTEM, PHP_INI_STAGE_RUNTIME); > + old_allow_url_fopen_list = PG(allow_url_fopen_list); > + if (!old_allow_url_fopen_list) { > + old_allow_url_fopen_list = ""; > + } > + zend_alter_ini_entry("allow_url_fopen", > sizeof("allow_url_fopen"), "*", 1, PHP_INI_SYSTEM, PHP_INI_STAGE_RUNTIME); > if (use_ssl && php_stream_locate_url_wrapper("https://", NULL, > STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC) == NULL) { > php_url_free(phpurl); > if (request != buf) {efree(request);} > add_soap_fault(this_ptr, "HTTP", "SSL support is not > available in this build", NULL, NULL TSRMLS_CC); > - zend_alter_ini_entry("allow_url_fopen", > sizeof("allow_url_fopen"), old_allow_url_fopen ? "1" : "0", 1, > PHP_INI_SYSTEM, PHP_INI_STAGE_RUNTIME); > + zend_alter_ini_entry("allow_url_fopen", > sizeof("allow_url_fopen"), old_allow_url_fopen_list, > strlen(old_allow_url_fopen_list), PHP_INI_SYSTEM, PHP_INI_STAGE_RUNTIME); > return FALSE; > } > > @@ -376,11 +379,11 @@ try_again: > php_url_free(phpurl); > if (request != buf) {efree(request);} > add_soap_fault(this_ptr, "HTTP", "Could not > connect to host", NULL, NULL TSRMLS_CC); > - zend_alter_ini_entry("allow_url_fopen", > sizeof("allow_url_fopen"), old_allow_url_fopen ? "1" : "0", 1, > PHP_INI_SYSTEM, PHP_INI_STAGE_RUNTIME); > + zend_alter_ini_entry("allow_url_fopen", > sizeof("allow_url_fopen"), old_allow_url_fopen_list, > strlen(old_allow_url_fopen_list), PHP_INI_SYSTEM, PHP_INI_STAGE_RUNTIME); > return FALSE; > } > } > - zend_alter_ini_entry("allow_url_fopen", > sizeof("allow_url_fopen"), old_allow_url_fopen ? "1" : "0", 1, > PHP_INI_SYSTEM, PHP_INI_STAGE_RUNTIME); > + zend_alter_ini_entry("allow_url_fopen", > sizeof("allow_url_fopen"), old_allow_url_fopen_list, > strlen(old_allow_url_fopen_list), PHP_INI_SYSTEM, PHP_INI_STAGE_RUNTIME); > > if (stream) { > if (client->url) {
Best regards, Marcus

Mark Evans

19 years ago
Hi Sara +1 from me, a very nice solution to the problem IMO Regards Marco

Ilia A.

19 years ago
On 16-Jan-07, at 8:07 PM, Sara Golemon wrote:
> allow_url_include has been bashed lately for being "not good > enough", and there is a kernel of truth to that, though where the > ultimate blame falls if of course a touchy subject.
Not really, I mean is it so difficult to expect the extension writer to know that if they are working with remote streams that they should set is_url to 1 rather then 0.
> So rather than continue the fight over who's shoulders the job of > security should fall on, how about the attached patch which puts a > little more power in the hands of the user/site-admin to control > what can be treated as a url include, and how it can be treated > that way.
I do not think that this is a good idea. Controlling security settings via INI is just a recipe for disaster and will only lead to problem due to poor configuration choices. Basically you are moving the "blame" from extension writers that provide stream wrappers (fairly limited group) onto a far larger group of users. Ilia Alshanetsky

Jochem Maas

19 years ago
Ilia Alshanetsky wrote:
> > On 16-Jan-07, at 8:07 PM, Sara Golemon wrote: > >> allow_url_include has been bashed lately for being "not good enough", >> and there is a kernel of truth to that, though where the ultimate >> blame falls if of course a touchy subject. > > Not really, I mean is it so difficult to expect the extension writer to > know that if they are working with remote streams that they should set > is_url to 1 rather then 0. > >> So rather than continue the fight over who's shoulders the job of >> security should fall on, how about the attached patch which puts a >> little more power in the hands of the user/site-admin to control what >> can be treated as a url include, and how it can be treated that way. > > I do not think that this is a good idea. Controlling security settings > via INI is just a recipe for disaster and will only lead to problem due > to poor configuration choices. Basically you are moving the "blame" from > extension writers that provide stream wrappers (fairly limited group) > onto a far larger group of users.
what what it's worth, my opinion (as a member of the 'larger group of users'): as an end user I'd rather have the control myself and be the one to blame, than be at the 'mercy' of extension writers - where I have little to no idea if an extension behaves or not (and if not if/when it might be corrected). I see no reason to think that hosting providers & or packages would think any differently ... unless their lazy and enjoy passing the buck all the time. this does presume that good documentation and best-practice recommendations are available. rgds, Jochem (php village idiot by profession)

Marcus Börger

19 years ago
Hello Ilia, Wednesday, January 17, 2007, 3:09:15 PM, you wrote:
> On 16-Jan-07, at 8:07 PM, Sara Golemon wrote:
>> allow_url_include has been bashed lately for being "not good >> enough", and there is a kernel of truth to that, though where the >> ultimate blame falls if of course a touchy subject.
> Not really, I mean is it so difficult to expect the extension writer > to know that if they are working with remote streams that they should > set is_url to 1 rather then 0.
Well these are two different things. One is a naming issue, where the name of a structure member is more than misleading. On the other hand we have the INI setting which currently only allows to chose between all and nothing. That means, if you need to enable one of the external url handlers then you are forced to allow them all and by that lowering your security settings. Sara's patch now gives a much better control. Regardless of whether extension writers read the docu or not. However we might wantto rename the structure member. [...] Best regards, Marcus

David Zülke

19 years ago
Sara, I assume this would also mean all userland stream wrappers become is_url=1? Anyway, +1. David Am 17.01.2007 um 02:07 schrieb Sara Golemon:

Sara Golemon

19 years ago
> I assume this would also mean all userland stream wrappers become is_url=1? > > Anyway, +1. >
This patch, by itself, doesn't affect the is_urlness of userspace wrappers. Whether or not we change their designation is up to a separate concensus (I'm in favor of it for the record). Funnily enough though, Pierre and I were just discussing the problem of userspace wrappers. Specifying all potential userspace wrapper names in a whitelist style allow_url_fopen setting isn't realistic, so we thought it might be a good idea to add a sort of "meta-wrapper" name to be used in the whitelist style. e.g. allow_url_fopen=file,http,ftp,user would allow those first three wrappers explicitly by name, plus any userdefined wrapper (regardless of specific name). For completeness, we might also add a metawrapper called "internal" for "All non-userspace based wrappers", though the specific usefulness of that is a little more iffy... -Sara

Richard Quadling

19 years ago
Sort of thinking out loud and not really sure if this is possible, but if a wrapper is NOT present (specifically denied) in allow_url_fopen, but "user" is present, could a user defined wrapper emulate the missing one, thereby bypassing the restriction? On 18/01/07, Sara Golemon <pollita@php.net> wrote:
> > I assume this would also mean all userland stream wrappers become is_url=1? > > > > Anyway, +1. > > > This patch, by itself, doesn't affect the is_urlness of userspace > wrappers. Whether or not we change their designation is up to a > separate concensus (I'm in favor of it for the record). > > Funnily enough though, Pierre and I were just discussing the problem of > userspace wrappers. Specifying all potential userspace wrapper names in > a whitelist style allow_url_fopen setting isn't realistic, so we thought > it might be a good idea to add a sort of "meta-wrapper" name to be used > in the whitelist style. e.g. allow_url_fopen=file,http,ftp,user > would allow those first three wrappers explicitly by name, plus any > userdefined wrapper (regardless of specific name). For completeness, we > might also add a metawrapper called "internal" for "All non-userspace > based wrappers", though the specific usefulness of that is a little more > iffy... > > -Sara > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php > >
-- ----- Richard Quadling Zend Certified Engineer : http://zend.com/zce.php?c=ZEND002498&r=213474731 "Standing on the shoulders of some very clever giants!"

Richard Lynch

19 years ago
On Tue, January 16, 2007 7:07 pm, Sara Golemon wrote:
> allow_url_fopen and allow_url_include continue to accept boolean flags > in order to behave just as they do now: true/on allows anything, > false/off allows only those wrappers without the is_url bit set.
+1, fwiw. As far as the "user" being able to implement something otherwise dis-allowed... Well, yeah, they could. I'm not sure who would really turn off an internal wrapper, then turn on "user" then be upset that somebody coded a work-around for a blocked internal wrapper... I mean, that just seems like an unlikely real-world sequence of events, in any decent work-place... I suppose if it's the case of malicious code getting executed, there'd be a point, but really, once you have arbitrary malicious PHP code getting executed on your box, it's kind of moot if they can then download more PHP code to execute, isn't it?...
-- Some people have a "gift" link here. Know what I want? I want you to buy a CD from some starving artist. http://cdbaby.com/browse/from/lynch Yeah, I get a buck. So?

Richard Quadling

19 years ago
Hmm. Yes. I see. Moot indeed. On 22/01/07, Richard Lynch <ceo@l-i-e.com> wrote:
> On Tue, January 16, 2007 7:07 pm, Sara Golemon wrote: > > allow_url_fopen and allow_url_include continue to accept boolean flags > > in order to behave just as they do now: true/on allows anything, > > false/off allows only those wrappers without the is_url bit set. > > +1, fwiw. > > As far as the "user" being able to implement something otherwise > dis-allowed... > > Well, yeah, they could. > > I'm not sure who would really turn off an internal wrapper, then turn > on "user" then be upset that somebody coded a work-around for a > blocked internal wrapper... I mean, that just seems like an unlikely > real-world sequence of events, in any decent work-place... > > I suppose if it's the case of malicious code getting executed, there'd > be a point, but really, once you have arbitrary malicious PHP code > getting executed on your box, it's kind of moot if they can then > download more PHP code to execute, isn't it?... > > -- > Some people have a "gift" link here. > Know what I want? > I want you to buy a CD from some starving artist. > http://cdbaby.com/browse/from/lynch > Yeah, I get a buck. So? > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php > >
-- ----- Richard Quadling Zend Certified Engineer : http://zend.com/zce.php?c=ZEND002498&r=213474731 "Standing on the shoulders of some very clever giants!"

David Zülke

19 years ago
My understanding is that this coudn't happen because a userspace stream would be flagged is_url. So unless someone turns off, say "ftp", and then adds "ftp" to the whitelist, there is no problem. And if anyone does that, he/she should seriously consider looking for a job where he/she can't mess things up that badly :P Am 22.01.2007 um 06:44 schrieb Richard Lynch: