Re: [PHP-DEV] Providing sandboxed versions of include and require language constructs
2012/3/7 Ángel González keis...@gmail.com On 07/03/12 00:04, Adam Jon Richardson wrote: It would be the responsibility of the framework or CMS or application to protect against this type of attack (which they do quite well.) When you can force a plugin to work through your API, you can take appropriate measures. When the plugin can avoid working through, say, a file API that protects against misuse by using the internal file functions, this is a much more difficult issue to mitigate. The key point is precisely, how do you ensure they can only call your API? The idea would be to have a default whitelist of internal functions that can be easily expanded per include as needed. That way, the script including another script can determine how much power/trust they're willing to hand off. For example: // EXAMPLE 1: included script would only be able to call functions found in default whitelist include_restricted('file/path1'); // EXAMPLE 2: included script would only be able to call functions found in default whitelist and PDO include_restricted('file/path2', $whitelist = array(SANDBOX_PDO)); The types of restrictions that involve restricting calls to internal functions (e.g., file()) are, at least conceptually, is straight forward. However, PDO has an object interface. For objects, I'm researching the idea of limiting the creation of new objects within the included script. That is to say that in example 1, the included script would raise an error if it tried to create a PDO object directly. However, in some situations, the framework or CMS may hand off a PDO object to the included script or expose a factory API (maybe the intent is to share a DB connection), and in this case, the sandbox would allow the PDO object to be utilized within the script. The idea is for the framework/CMS to be the gatekeeper for all of the applications resources, and if the framework designers want to hand off an object for use, then that fits with the general model I'm proposing. Right now, it's very difficult to enforce any restrictions on included scripts because they have access to all of the internal functions available to the framework/CMS (using something like the disable_functions directive limits the framework/CMS too much and works from a blacklist approach.) I'm not saying this would be easy to implement, or that it would be perfectly secure. I am saying that it's worth careful examination and that there are many potential solutions that could make things better in terms of application security. Thanks for the feedback, Adam
Re: [PHP-DEV] Providing sandboxed versions of include and require language constructs
On Tue, March 6, 2012 3:30 am, Florian Anderiasch wrote: Security by blacklist almost always isn't security... You're bound to miss one of the functions you should have blacklisted, but didn't. Something like Drupal would be crippled by this because major extensions used by all rely on access that would probably want to be blocked. So then they'd have to come up with a blessed list of extension to not block, and then... Nice idea, in the abstract, but I don't think it will work out to be very useful in the Real World (tm). -- brain cancer update: http://richardlynch.blogspot.com/search/label/brain%20tumor Donate: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclickhosted_button_id=FS9NLTNEEKWBE -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Providing sandboxed versions of include and require language constructs
On Mon, Mar 12, 2012 at 5:08 PM, Richard Lynch c...@l-i-e.com wrote: On Tue, March 6, 2012 3:30 am, Florian Anderiasch wrote: Security by blacklist almost always isn't security... You're bound to miss one of the functions you should have blacklisted, but didn't. Agreed. The approach I'm developing would be a whitelisting approach. Something like Drupal would be crippled by this because major extensions used by all rely on access that would probably want to be blocked. So then they'd have to come up with a blessed list of extension to not block, and then... The idea would be to make it easy to add to the default whitelist per include. Nice idea, in the abstract, but I don't think it will work out to be very useful in the Real World (tm). I'm working on documenting the ideas and refining the approach. I think it will hold significant value, but a few years ago I also thought that WebOS would become a major player in the mobile market :) Adam P.S. - Thankful to see that your recent update on your medical prognosis, Richard.
Re: [PHP-DEV] Providing sandboxed versions of include and require language constructs
On 07/03/12 00:04, Adam Jon Richardson wrote: It would be the responsibility of the framework or CMS or application to protect against this type of attack (which they do quite well.) When you can force a plugin to work through your API, you can take appropriate measures. When the plugin can avoid working through, say, a file API that protects against misuse by using the internal file functions, this is a much more difficult issue to mitigate. The key point is precisely, how do you ensure they can only call your API? -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Providing sandboxed versions of include and require language constructs
Hi, On 03/06/2012 08:34 AM, Adam Jon Richardson wrote: [...] 1) Internal functions seen as universally safe would by default be allowed (e.g, str_replace(), array_pop(), etc.) 2) Unsafe internal functions would have to be explicitly declared (e.g., file(), stream_*, etc.) 3) Any includes or requires within the sandboxed code would be forced to meet the same restrictions. (tricky) 4) Code containing unsafe functions not included in the whitelist would raise an error. [...] Thoughts? Isn't that basically what all template engines tried to solve before with giving you a defined subset of tokens that are more or less directly converted to php code? The benefit I see is that plugin developers wouldn't need to learn a new DSL (domain-specific language), but use PHP code. Just that it's not PHP if you disable 90% of the functions available. While the idea is certainly not bad, I'm not sure you could write sensible plugins for applications with only a few string functions at hand. My gut instinct tells me you'll run into something like I wish I had this dir() to get the files in this directory more sooner than later. Last plugin (for Drupal) I wrote for example hooked into the File API and saves/retrieves uploads to/from MogileFS. So that's file access AND network access, and those would quite probably the first on the list to be blacklisted. And if you only blacklist a few, disable_functions might be enough. To sum it up, to solve this problem I'd be more thinking about creating a specific DSL (like puppet) to fill my needs and not try to make people write some sort of 50%-PHP with constant lookup which functions are allowed and which are not. Greetings, Florian -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Providing sandboxed versions of include and require language constructs
Hi! Thoughts? This is a fine idea, however actually doing it is not that easy. Note that knowing which function is safe is pretty hard, but that's only a start. Plugin code, for example, can call functions outside plugin context, while passing all kinds of arguments - is it safe or not? It depends on the context - e.g. plugin may need access to the database - directly or through some API - but that opens the door to various SQL injections and other mischief, etc. etc. So while the idea is fine, designing a working sandbox is a very complicated task. That said, if you have any ideas - you're welcome to propose. -- Stanislav Malyshev, Software Architect SugarCRM: http://www.sugarcrm.com/ (408)454-6900 ext. 227 -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Providing sandboxed versions of include and require language constructs
On Tue, Mar 6, 2012 at 3:30 AM, Florian Anderiasch flor...@anderiasch.dewrote: Isn't that basically what all template engines tried to solve before with giving you a defined subset of tokens that are more or less directly converted to php code? The benefit I see is that plugin developers wouldn't need to learn a new DSL (domain-specific language), but use PHP code. Just that it's not PHP if you disable 90% of the functions available. I agree, many template engines do offer a controlled set of language constructs that limit the attack surface. However, DSL's tend to be focused on one specific problem area (such as templating, as you noted) as opposed to providing general programming capabilities, so building plugins in a DSL can be quite limiting in terms of potential power: http://martinfowler.com/bliki/DomainSpecificLanguage.html As another option, one could always develop a full-fledge programming language that compiles down to PHP (similar to CoffeeScript's compiling to JavaScript.) One can then use the language to abstract away calls to functions deemed unsafe without explicit permission. However, this requires learning a new programming language and would require the consumer of the script to perform compilation to ensure the security. I'm not sure how many functions would be disabled, but I estimate it's a much lower number than 90%. For instance, if a function is pure (i.e., has no side effects), that function would be considered safe. That said, I'll start sifting this list of functions and see what list I come up with: http://php.net/quickref.php While the idea is certainly not bad, I'm not sure you could write sensible plugins for applications with only a few string functions at hand. My gut instinct tells me you'll run into something like I wish I had this dir() to get the files in this directory more sooner than later. Last plugin (for Drupal) I wrote for example hooked into the File API and saves/retrieves uploads to/from MogileFS. So that's file access AND network access, and those would quite probably the first on the list to be blacklisted. And if you only blacklist a few, disable_functions might be enough. Valid points. Your Drupal plugin example could use several of the functions initially blacklisted. However, the developer would then be able to, upon reading the documentation and requirements for your plugin OR seeing the error raised when attempting to sandbox your script, make an informed decision as to how much they trust you, the provider of the script, and, whether the perceived risk is worth the value. If the value is enough, the developer would then be able to add the needed functions to the whitelist and run your plugin. Of note, the sandbox I'm suggesting would only impact internal functions within files included with the sandboxing function. If Drupal, for example, offered a file API and made it available to your plugin through the scoping rules inherent in the application, you would be able to call those functions without issue. The sandboxing would only limit direct calls to unsafe, internal functions. The idea is to limit the access to the environment that the framework or CMS can't properly limit. They can already limit access to their environment through the API, and this proposal would trust them to do that. The disable_functions directive is indeed very handy, but it forces you to give up the functions throughout the entire environment, whereas the sandboxing would be limited to the scope of specific includes. Additionally, shared host environments don't allow you to adjust this setting. To sum it up, to solve this problem I'd be more thinking about creating a specific DSL (like puppet) to fill my needs and not try to make people write some sort of 50%-PHP with constant lookup which functions are allowed and which are not. The hope would be that you wouldn't have to constantly look up the functions that are allowed. Rather, you'd use the functions you need and the consumer of your plugin would decide if your plugin merited trusting you with the unsafe internal functions you used. While the consumer might not be able to audit every plugin they use, the sandboxing would bring to light the plugins that needed extra attention and caution. Excellent feedback, Florain. Thanks! Adam
Re: [PHP-DEV] Providing sandboxed versions of include and require language constructs
On Tue, Mar 6, 2012 at 4:38 AM, Stas Malyshev smalys...@sugarcrm.comwrote: Hi! Thoughts? This is a fine idea, however actually doing it is not that easy. Note that knowing which function is safe is pretty hard, but that's only a start. Plugin code, for example, can call functions outside plugin context, while passing all kinds of arguments - is it safe or not? It depends on the context - e.g. plugin may need access to the database - directly or through some API - but that opens the door to various SQL injections and other mischief, etc. etc. So while the idea is fine, designing a working sandbox is a very complicated task. That said, if you have any ideas - you're welcome to propose. The sandbox I'm considering would only impact the ability to directly call internal functions. The idea rests on the hope that the framework or CMS provides a security model that protects the integrity of their own environment. The framework can for example hand off whatever state variables are deemed appropriate and necessary to a plugin. The framework can make public whatever methods are appropriate and necessary. However, the framework can't currently limit the direct calls to internal functions (without parsing the PHP source and it's dependencies), which could allow the plugin developer to circumvent the security policies of the framework. Indeed, the complexity is extreme, even for the limited scope of this idea. And, avoiding complexity for the developers using the sandboxed version would be difficult, too. I'm wondering if it would be easier to allow constants representing entire classes of functionality. For example: include_restricted('file/path', $whitelist = array('SANDBOX_FILE', 'SANDBOX_PDO', 'SANDBOX_MYSQL', 'SANDBOX_SOCKET')); If an error was raised because an included file required additional access, the error message could detail the exact constant(s) that would have to be whitelisted for the include to be allowed. Thank you for the feedback, Stas. The questions and concerns raised in this discussion help considerably. Adam
RE: [PHP-DEV] Providing sandboxed versions of include and require language constructs
Hi! Thoughts? This is a fine idea, however actually doing it is not that easy. Note that knowing which function is safe is pretty hard, but that's only a start. Plugin code, for example, can call functions outside plugin context, while passing all kinds of arguments - is it safe or not? It depends on the context - e.g. plugin may need access to the database - directly or through some API - but that opens the door to various SQL injections and other mischief, etc. etc. So while the idea is fine, designing a working sandbox is a very complicated task. That said, if you have any ideas - you're welcome to propose. The sandbox I'm considering would only impact the ability to directly call internal functions. The idea rests on the hope that the framework or CMS provides a security model that protects the integrity of their own environment. The framework can for example hand off whatever state variables are deemed appropriate and necessary to a plugin. The framework can make public whatever methods are appropriate and necessary. However, the framework can't currently limit the direct calls to internal functions (without parsing the PHP source and it's dependencies), which could allow the plugin developer to circumvent the security policies of the framework. Indeed, the complexity is extreme, even for the limited scope of this idea. And, avoiding complexity for the developers using the sandboxed version would be difficult, too. I'm wondering if it would be easier to allow constants representing entire classes of functionality. For example: include_restricted('file/path', $whitelist = array('SANDBOX_FILE', 'SANDBOX_PDO', 'SANDBOX_MYSQL', 'SANDBOX_SOCKET')); If an error was raised because an included file required additional access, the error message could detail the exact constant(s) that would have to be whitelisted for the include to be allowed. Thank you for the feedback, Stas. The questions and concerns raised in this discussion help considerably. Adam I've seen a simple safe code evaluator put together using token_get_all. I'm certain that you could create an include_restricted() function in userland using a similar system: walk through the tokens looking for anything forbidden (this will be tricky, because there are a lot of nooks that things could hide, like superglobals), then if everything looks good include the file. Use a caching system of some sort to improve performance and eliminate redundant checks. I seriously doubt that this would ever get implemented in the core though. PHP has been moving away from this sort of thing (and for good reason). Attempting a one size fits all sandbox in the core just doesn't make any sense. John Crenshaw Priacta, Inc. -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Providing sandboxed versions of include and require language constructs
On 03/06/2012 06:03 AM, John Crenshaw wrote: I've seen a simple safe code evaluator put together using token_get_all. I'm certain that you could create an include_restricted() function in userland using a similar system: walk through the tokens looking for anything forbidden (this will be tricky, because there are a lot of nooks that things could hide, like superglobals), then if everything looks good include the file. Use a caching system of some sort to improve performance and eliminate redundant checks. Yeah, a token approach wouldn't work. $a = 'mysql_connect'; $a($args); trivially circumvents that. It would have to build new function/class hashtables directly which is rather expensive so from a performance perspective this would not be pretty. I suppose an opcode cache could cache these to speed this up quite a bit, but there would still need to be extra gear in place to manage multiple hash tables and some code to check if there was an overriding hash to be used for every op_array. -Rasmus -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Providing sandboxed versions of include and require language constructs
On 06/03/12 14:04, Adam Jon Richardson wrote: The sandbox I'm considering would only impact the ability to directly call internal functions. The idea rests on the hope that the framework or CMS provides a security model that protects the integrity of their own environment. The framework can for example hand off whatever state variables are deemed appropriate and necessary to a plugin. The framework can make public whatever methods are appropriate and necessary. However, the framework can't currently limit the direct calls to internal functions (without parsing the PHP source and it's dependencies), which could allow the plugin developer to circumvent the security policies of the framework. Indeed, the complexity is extreme, even for the limited scope of this idea. And, avoiding complexity for the developers using the sandboxed version would be difficult, too. I'm wondering if it would be easier to allow constants representing entire classes of functionality. For example: include_restricted('file/path', $whitelist = array('SANDBOX_FILE', 'SANDBOX_PDO', 'SANDBOX_MYSQL', 'SANDBOX_SOCKET')); If an error was raised because an included file required additional access, the error message could detail the exact constant(s) that would have to be whitelisted for the include to be allowed. Thank you for the feedback, Stas. The questions and concerns raised in this discussion help considerably. Adam It's not that easy. The internal functions could be splitted to safe/unsafe (according tosome definition, which would itself be a controversial one) but all functions defined outside would be injection candidates, too. Suppose you modified the function hash table to store if it's a limited function or it should be run with high privileges. Now, you need to audit the whole framework so that no can be tricked into doing more things than it should, if called from low-privilege code. Which is pretty hard when that code could be corrupting your variables. For instance, a safe framework function to perform database queries, could become unsafe by changing the db configuration (usually stored on globals), allowing connections to arbitrary servers. Or a malicious plugin could register a class with the same name as a framework one, before the autoloader loads the right one, and have it used by privileged code. PHP is not designed to use it that way, so unless there is an high level way to do it, it's probably impossible to do right. Maybe you can perform a full global replacement when calling untrusted code. That might work. -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Providing sandboxed versions of include and require language constructs
2012/3/6 Ángel González keis...@gmail.com On 06/03/12 14:04, Adam Jon Richardson wrote: The sandbox I'm considering would only impact the ability to directly call... It's not that easy. The internal functions could be splitted to safe/unsafe (according tosome definition, which would itself be a controversial one) Yes, perhaps controversial, but using an objective criterion like purity would aid the effort. but all functions defined outside would be injection candidates, too. The idea I put forth would only deal with internal functions. Frameworks and CMS's would still be on-the-hook to validate incoming data and escape data according to context for all of the functions that they expose to the plugin/library. And this would still be very beneficial. As framework developer, I can validate the inputs coming into my API hooks and escape the outputs according to context. However, when plugin developers can call the internal functions and circumvent my protections, this is a more difficult issue to solve en masse. Suppose you modified the function hash table to store if it's a limited function or it should be run with high privileges. I'm not promoting a privilege-based system of high and low privileges. Rather, I'm posing the possibility of limiting the access of included code to internal functions/objects. Now, you need to audit the whole framework so that no can be tricked into doing more things than it should, if called from low-privilege code. Which is pretty hard when that code could be corrupting your variables. For instance, a safe framework function to perform database queries, could become unsafe by changing the db configuration (usually stored on globals), allowing connections to arbitrary servers. It would be the responsibility of the framework or CMS or application to protect against this type of attack (which they do quite well.) When you can force a plugin to work through your API, you can take appropriate measures. When the plugin can avoid working through, say, a file API that protects against misuse by using the internal file functions, this is a much more difficult issue to mitigate. Or a malicious plugin could register a class with the same name as a framework one, before the autoloader loads the right one, and have it used by privileged code. PHP is not designed to use it that way, so unless there is an high level way to do it, it's probably impossible to do right. Maybe you can perform a full global replacement when calling untrusted code. That might work. Javascript wasn't designed this way, either. However, tools like Secure EcmaScript go a long way towards protecting against the attacks mashups typically must prevent by protecting/limiting the environment: http://code.google.com/p/es-lab/wiki/SecureEcmaScript http://www.infoq.com/presentations/Secure-Mashups-in-ECMAScript-5 Thanks for the feedback, Angel. Adam
[PHP-DEV] Providing sandboxed versions of include and require language constructs
Plugins are a big deal (see http://oneofmanyworlds.blogspot.in/2012/03/difficult-decision.html for a recent example.) In this era of mashups and breakneck innovation, developers must rely on vast amounts of code they've never seen, let alone audited. Wordpress, Drupal, and many other tools developed in PHP make plugin development easy and extremely powerful. While these tools constantly work to improve security (and, at least relatively, do a solid job most of the time), there remains significant challenges due to globally accessible functions that allow manipulation of the environment (files, DB's, networking, etc.) Any plugin can use these global functions to work around the security restrictions imposed by the framework, library, or CMS. While code audits can locate the offending scripts, this is a challenging task, both in terms of time AND abilities. Languages and/or environments that can mitigate these issues for the developer, while far from fool proof, do offer real value on the security front. Lua provides the ability for developers to limit the functions available in the current environment: http://lua-users.org/wiki/SandBoxes PHP does have an extension that offers several forms of sandboxing: runkit. However, it's often not available in shared host environments. The include (and require) construct is the front door for any plugin code. What if PHP offered functions that implemented sandboxed versions of the include and require language constructs (e.g., included_restricted('file/path', $functions = array('file', 'file_get_contents')))? Functional specs could include: 1) Internal functions seen as universally safe would by default be allowed (e.g, str_replace(), array_pop(), etc.) 2) Unsafe internal functions would have to be explicitly declared (e.g., file(), stream_*, etc.) 3) Any includes or requires within the sandboxed code would be forced to meet the same restrictions. (tricky) 4) Code containing unsafe functions not included in the whitelist would raise an error. There would be a performance hit for code that actually used the sandboxed functions to include scripts, but for many applications, I suspect this would be worth the hit. Security is becoming more important by the day (just ask github: http://homakov.blogspot.com/2012/03/how-to.html#), and empowering the developer with tools to enforce greater restrictions on the ever-growing heaps of unaudited code seems wise. Thoughts? Adam