====== Optional PHP tags by php.ini and CLI options ====== * Version: 1.6 * Date Created: 2012-04-01 * Date Modified: 2014-02-12 * Author: Moriyoshi Koizumi , Yasuo Ohgaki * Status: Inactive * First Published at: http://wiki.php.net/rfc/nophptags * Other formats .. ===== Summary ===== PHP has been known to be more vulnerable to script inclusion attacks than other languages. PHP is made for Web and embedding feature is valuable for easier web application development. However, embedded scripts are serious security risk as it can executes any PHP code in any files. PHP is made for web application and today's web application should have strong security. This RFC proposes PHP open tags to be optional, template mode switch and script only include feature. ==== Related RFC ==== https://wiki.php.net/rfc/source_files_without_opening_tag ===== Proposal ===== === Open Issue === * We may change include()/require() behavior according to template_mode. i.e. include()/require() behaves like script() when template_mode=on. And template_mode could be PHP_INI_ALL. i.e. Adoption of this RFC could be [[https://wiki.php.net/rfc/nophptags#example_usage|as few as 3 lines of PHP code]] with this. * We may only introduce script()/script_once(), even if it seems a little odd. i.e. Directly called script always requires "'' open tag. * Ignore close tags (''?>'' and ''%>'') completely. Raising error is preferred, but ignore them for better compatibility. i.e. There are many scripts that have ''?>'' at the end even for program only scripts. * When template_mode=on * Exactly the same as now. ==== Future Scope ==== * script()/script_once() allows " function render_template($template, $template_vars) { ini_set('template_mode', 'on'); // Older PHP ignores include($template, $template_vars); // Or use any other method to render. ini_set('template_mode', 'off'); // Older PHP ignores } For better security, program only script should use script()/script_once() as it does not allow embedded mode. To be compatible with older PHP, user has to define their own script()/script_once(). if (PHP_VERSION_ID < 50600) { // User have to use () for script/script_once for compatibility function script($php_script) { // Does not inherit scope, but it's not issue for most program only scripts. // Optional: May use tokenizer if $php_script contains script only or not return include($php_script); } function script_once($php_script) { return include_once($php_script); } } ===== Patch ===== This is PoC patch that only controls template mode. No script()/script_once() implementation. https://gist.github.com/2266652 ===== Vote ===== VOTE: 2014/2/16 - 2014/2/22 Most of LFI can be prevented by using script only program inclusion. * Yes * No Directly called script cannot use script()/script_once(). Remove inconsistency between directly executed script and indirectly executed script. * Yes * No Thank you for voting. ===== Implementation ===== After the project is implemented, this section should contain - the version(s) it was merged to - a link to the git commit(s) - a link to the PHP manual entry for the feature ===== Discussions ===== ==== Motivation of this RFC ==== Motivation to have this RFC is - "File Includes" is fatal security breach. - The reason why PHP is unsecure to "File Include" than other language is "Mandatory embed mode" - Non mandatory embed mode gives option users to better security. With this RFC, PHP could be as safe as other scripting languages with respect to file includes. This RFC is fully compatible with current code. Writing backward compatible code is as few as 3 lines. Most of security measures are not perfect solutions, but mitigation, just like canary and DEP. I suppose people who are concerned with security understand the value of these protections. Is there any good reasons not to have non mandatory embedded mode as a additional security measure? Why not to make it harder for attackers to exploit? In short, I'm really annoyed to hear "PHP is insecure than Ruby/Perl/Python/etc" This must be noted. Even if this RFC emphases on security, this RFC is not for introducing a new security measure. This RFC is for changing embedded only language to non-embedded/embedded language. Side effect of this change will provide better security against LFI. ==== Why this is better than now? ==== * **Framework authors** * Framework developers will have effective protection against suicide code like "include $_REQUEST['var'];" in user scripts. * If framework adopts template_mode=off, the suicide code above will raise syntax errors for LFI code execution and information disclosure attack patterns. * Note: If the file is valid PHP code, it's possible executing code. However, the risk is the same or less compare to Ruby/Perl/Python/etc. * It could be as few as 3 lines to adopt template_mode=off. * Framework developers are not required to rewrite include/require statements. * Framework can be compatible with older PHP. * Fully compatible with current code. (template_mode=on) * Mostly compatible with current code. (template_mode=off) * where it is possible. * It should be inserted at beginning of file as much as possible. * Location to be inserted depends on data file, but data file has reserved area. Inject into the area. * Previous requirement is almost impossible to enforce, since PHP may read any file with permission. (e.g. inserting in /etc/passwd is possible, but it is not feasible obviously. ) * Consider template_mode=off, since embedded mode is dangerous by its nature. * When **template_mode=off** in php.ini or bootstrap script, * Enable template_mode only when it is absolutely required. * If there are free format data files, add some header so that LFI causes syntax error. * Note: When template_mode=off, even if programmer dropped all protections, LFI would result in syntax errors in most cases. ==== A lot of effort will be needed to adopt template_mode?! ==== * No. Users may stick to current behavior. Current behavior(template_mode=on) is the default. * Even if users decided to adopt templat_mode=off, the changes that are required is a few as 3 lines. For modern frameworks, it would be simple task. * Framework users do not have to do nor learn the change as long as they follow their framework practice. ==== template_mode is similar to allow_url_include ==== * allow_url_include: * enable only when url include is needed. * prevents RFI which results in critical security incident. * template_mode: * enable only when template mode is needed. * prevents LFI which results in critical security incident. ==== template_mode=off is safe guard ==== * This is not an direct security mesure, but a safe guard for risk mitigation. * It is a side effect of making PHP non-mandatory embedded language. * Mitigation factor is large if programmer follow guideline. * Think it as canary protection for stack smashing or DEP for heap overflow. * Since LFI is critical, additional protections are preferred whenever possible. ==== template_mode=off could be security issue ==== * When template_mode=off, PHP script may be exposed. * Files contains open tag "". However, this might be a issue still. * PHP scripts that aren't be accessed by users should be located other than docroot. This is good practice without this RFC also. * PHP users are used to such case(?) since short tags were optional for a long time. ==== Security measure or accident? ==== * Script only mode causes syntax error for LFI attacks, but it's an accident. * Many security measures are rely on accidental protections. * ALSR is one of a security by accident so that attacker's guess would not work. ===== Background ===== Compare to other languages such as Ruby/Perl/Phthon/Lua/etc, current PHP is known to be weak for script injections/information disclosure. This proposal aims to reduce the LFI(Local File Include) risk to other scripting language level by optional embedded scripting mode. PHP is an embedded language since it was born. To execute a PHP code, PHP tag is required and PHP tag is mandatory. Mandatory Embed mode was reasonable 10 years ago, but it became less reasonable with recent framework adoption. PHP has security issue known as LFI(Local File Include)/RFI(Remote File Include). The risk of LFI/RFI was reduced by null byte check in fopen wrapper and allow_url_include php.ini option. However, there is remaining risk that cannot be ignored. LFI/RFI is fatal security error. Currently, LFI prevention is upto programmers and fatal FLI may happen anywhere in PHP script. It is preferred to have systematic approach to reduce LFI risk as much as possible. This RFC provides a additional protection for LFI by optional embedded mode. === Mandatory Embed mode = Less Security === There are countermeasures allow_url_include=off for RFI, Null byte check in fopen wrapper and open_basedir for LFI. However, injecting PHP code in a file is easy because of the mandatory embedded script nature. Simple vulnerability in include()/require() could result in a fatal code execution and/or fatal information disclosure security incident. PHP script inclusion detection may be done for data files. However, it's not a simple task. * should be checked. "