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.
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.cRCS 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; /* sothat PG(allow_url_fopen) can be respected */
int is_url; /* sothat 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.cRCS 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, "URLfile-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 ZTSchar *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 thatcompress.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 specifiedwhen 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 asan 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 asan 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.cRCS 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.cRCS 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,NULLTSRMLS_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,NULLTSRMLS_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
Hi Sara
+1 from me, a very nice solution to the problem IMO
Regards
Marco
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
Ilia Alshanetsky 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)
Hello Ilia,
Wednesday, January 17, 2007, 3:09:15 PM, you 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
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:
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.
Index: main/php_globals.hRCS 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.cRCS 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 theprotocol 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, "Plainfileswrapper 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, "Plainfileswrapper disabled");
php_error_docref(NULL TSRMLS_CC, E_WARNING, "file:// wrapperis 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 isdisabled 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 isdisabled 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 areallowed */
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));
+#endifchar **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 italone */
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 bemore 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 lowercased, 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 escapeis_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 aninclude 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 aninclude 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.cRCS 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,NULLTSRMLS_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,NULLTSRMLS_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) {
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
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?
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
Zend Certified Engineer : http://zend.com/zce.php?c=ZEND002498&r=213474731
"Standing on the shoulders of some very clever giants!"
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?
Hmm. Yes. I see. Moot indeed.
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
Zend Certified Engineer : http://zend.com/zce.php?c=ZEND002498&r=213474731
"Standing on the shoulders of some very clever giants!"
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:
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?