rfc:nophptags

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

rfc:nophptags [2012/04/12 02:51]
yohgaki [What protection should be done for LFI?]
rfc:nophptags [2014/02/12 07:49] (current)
yohgaki
Line 1: Line 1:
 ====== Optional PHP tags by php.ini and CLI options ====== ====== Optional PHP tags by php.ini and CLI options ======
-  * Version: 1.4 +  * Version: 1.6 
-  * Date: 2012-04-12 +  * Date Created: 2012-04-01 
-  * Author: Moriyoshi Koizumi <​moriyoshi@php.net>​ Yasuo Ohgaki <​yohgaki@ohgaki.net>​+  * Date Modified: 2014-02-12 
 +  * Author: Moriyoshi Koizumi <​moriyoshi@php.net>​Yasuo Ohgaki <​yohgaki@ohgaki.net>​
   * Status: Under Discussion   * Status: Under Discussion
   * First Published at: http://​wiki.php.net/​rfc/​nophptags   * First Published at: http://​wiki.php.net/​rfc/​nophptags
Line 9: Line 10:
  
 ===== Summary ===== ===== Summary =====
-This RFC proposes PHP open tags to be optional. 
  
-==== Compatibilities ====+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. ​
  
-  * No new function nor parameters. +This RFC proposes PHP open tags to be optional, template mode switch and script only include feature.
-  * Fully compatible with current code. +
-  * Adopting ​RFC could be as few as 3 lines. +
-  * New code can be fully compatible with OLD systems.+
  
-==== Possible issues ==== 
- 
-  * NEW code that omits PHP open tags may be disclosed. 
- 
-==== Benefits ==== 
- 
-  * Transition is very easy, compatible for both forward/​backward not like the related RFC. 
-  * Writing "<?​php"​ at the top of code is highly recommended always. It's good for people who like embedded nature of PHP. 
-  * People who don't want to write script open tags don't have to write it at their own risks. 
-  * LFI becomes difficult. LFI attacks result in syntax errors almost always instead of **code execution** and/or **massive information disclosure**. 
-    * Embedded mode is weak to LFI. It is a characteristics of embedded language. Non-embedded mode makes PHP much stronger than now against LFI. 
-    * Related RFC does not address this issue. 
-  * [[nophptags#​why_this_is_better_than_now|Why this is better than now]] 
-==== Details ==== 
-  * [[nophptags#​discussions|Discussion]] 
-  * [[nophptags#​background|Background]] 
 ==== Related RFC ==== ==== Related RFC ====
  
 https://​wiki.php.net/​rfc/​source_files_without_opening_tag https://​wiki.php.net/​rfc/​source_files_without_opening_tag
 +
 ===== Proposal ===== ===== Proposal =====
  
-  * Add flag that controls embed(template) feature of PHP.+=== Open Issue ===
  
-Flag to control embed (templatemode+  * 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 "<?​php",​ while script() does not.
  
-php.ini+==Add flag that controls embed(template) feature of PHP==
  
-  template_mode = on   ; On by DEFAULTPHP_INI_ALL +Flag to control embed (template) mode for directly called scripts(e.g. http://some/foo.php or php bar.php Directly executing scripts are script accessed by browser directly, script executed from CLI binary.)
-                       ; On"<?php" ​or like is requried. +
-                       ; Off: Open tag is not required.+
  
-CLI+NOTE: **PHP script that has a "<?​php"​ or like at the top of script works regardless of template_mode.**
  
-  php -foo.php ​ # template mode. "<?​php"​ is required. DEFAULT +1) php.ini 
-  php -foo.php ​ # non-template mode. "<?​php"​ is not required.+ 
 +  template_mode = On   ​; On by default. PHP_INI_SYSTEM. 
 +                       ; On: "<?​php"​ or like is requried for directly executing script. 
 +                       ; Off: Open tag is not required for directly executing script. 
 + 
 + 
 + 
 +2) Environment variable 
 + 
 +  PHP_TEMPLATE_MODE=1 ​ # O for disable. No default. 
 + 
 +3) CLI 
 + 
 +  ​php -foo.php ​ # template mode. "<?​php" ​or like is required. DEFAULT 
 +  php -foo.php ​ # non-template mode. "<?​php" ​or like is not required. 
 + 
 +==Introduce functions(language constructs) includes program only script== 
 + 
 +4) New functions to include program only script. 
 + 
 +  script() - Includes script only file. Other than that. It behaves like include() 
 +  script_once() - Includes script only file. Other than that. It behaves like include_once() 
 + 
 +These are not affected by template_mode at all. These are always script only mode(template_mode=off). "<?​php"​ or like is only allowed at the top of a script. 
 + 
 +==Existing functions include/​require program and template scripts== 
 + 
 +5) include()/​require behavior does not change. 
 + 
 +  include()/​include_once()/​require()/​require_once() does not change behavior. 
 + 
 +These are not affected by template_mode at all. These are always embedded mode(template_mode=on). 
 + 
 +==Behaviors== 
 + 
 +6) Template mode behavior
  
   * When template_mode=off   * When template_mode=off
-    * Allow users to start PHP statements from the top of the script without putting open tags such as ''<?​php''​. +    * Only directly executed ​PHP scripts are affected.
-    * Complete removal of esoretic ''<​script lanuage="​PHP">''​ open tag.+
     * Allow open tags (''<?​php'',​ ''<?'',​ ''<​%''​) only at the top of the script for compatibility,​ and issue a parse error when used in other places.     * Allow open tags (''<?​php'',​ ''<?'',​ ''<​%''​) only at the top of the script for compatibility,​ and issue a parse error when used in other places.
-    * Ignore close tags (''?>''​ and ''​%>''​) completely.+    ​* Complete removal of ''<​script lanuage="​PHP">''​ 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 "<?​php"​ or like at the top of script. This is only for easier transition. It may be removed for PHP 7 or later. It may apply to directly called scripts. Security sensitive information should not be written into script directly. Good deployment tool and code should be able to use environment variables for these. 
 +  * Use of environment variable is difficult for self contained applications unless there is standard deployment tool. Creating general purpose deployment tool is hard since there are many web servers to support and configuration differs even when web server is the same. If there is no standard deployment tool, we may keep allowing to have "<?​php"​ or like at the top of scripts. 
 + 
 +==== Compatibility ==== 
 + 
 +  * Fully compatible with current code. i.e. include()/​require() works as it is now regardless of template mode or not. No compatibility issue at all. 
 +  * Adopting RFC could be lines of change. (Excluding script()/​script_once() Open Issue) 
 +  * Introduce script()/​script_once() for explicit script inclusion. i.e. script()/​script_once() always execute script, no embedding mode at all. 
 +  * New code can be fully compatible with OLD systems. i.e. Users may write script() function wraps include(). 
 + 
 +==== Possible issues ==== 
 + 
 +  * New code that omits PHP open tags may be disclosed. For maximum security, user may use "<?​php"​ at be beginning of PHP scripts contains sensitive data. (e.g. password/​API key/etc. Simple configuration/​code error is obvious) 
 + 
 +==== Benefits and Tips==== 
 + 
 +  * PHP can be as secure as other languages against local file inclusion(LFI). 
 +  * LFI becomes difficult. LFI attacks result in syntax errors almost always instead of **attack code execution** and/or **massive information disclosure**. 
 +    * Embedded mode is weak to LFI. It is a characteristics of embedded language. Non-embedded mode makes PHP much stronger than now against LFI. 
 +    * [[https://​wiki.php.net/​rfc/​source_files_without_opening_tag|Related RFC]] does not address this issue. 
 +    * People do make mistakes with embed everything by default. Some recent LFI issues. 
 +      * [[http://​packetstormsecurity.com/​files/​96996/​Joomla-XMovie-1.0-Local-File-Inclusion.html|Joomla XMovie 1.0 Local File Inclusion]] 
 +      * [[http://​seclists.org/​bugtraq/​2012/​Apr/​53|CitrusDB 2.4.1 - LFI/SQLi Vulnerability]] 
 +      * [[http://​packetstormsecurity.org/​files/​111075/​vtiger-lfi.txt|Vtiger 5.1.0 Local File Inclusion]] 
 +      * [[http://​packetstormsecurity.org/​files/​110906/​onefilecms-lfi.txt|OneFileCMS 1.1.5 Local File Inclusion]] 
 +      * [[http://​packetstormsecurity.com/​files/​125039/​Shadowbox-Local-File-Inclusion.html|Shadowbox Local File Inclusion]] 
 +      * [[http://​packetstormsecurity.com/​files/​124589/​xBoard-5.0-5.5-6.0-Local-File-Inclusion.html|xBoard 5.0 / 5.5 / 6.0 Local File Inclusion]] 
 +      * [[http://​packetstormsecurity.com/​files/​124321/​Zimbra-Local-File-Inclusion.html|Zimbra Local File Inclusion]] 
 +      * [[http://​packetstormsecurity.com/​files/​123192/​Monsta-FTP-1.3-Local-File-Inclusion.html|Monsta FTP 1.3 Local File Inclusion]] 
 +      * [[http://​packetstormsecurity.com/​files/​120921/​AContent-1.3-Local-File-Inclusion.html|AContent 1.3 Local File Inclusion]] 
 +      * [[http://​packetstormsecurity.com/​files/​121347/​Fork-CMS-Local-File-Inclusion.html|Fork CMS Local File Inclusion]] 
 +      *and [[http://​packetstormsecurity.com/​search/?​q=LFI|many more]].  
 +    * [[nophptags#​why_this_is_better_than_now|Why this is better than now]] 
 +  * Transition is very easy, compatible for both forward/​backward not like the related RFC. 
 +  * Writing "<?​php"​ at the top of code is highly & always recommended for script contains security sensitive information. It's good for people who like embedded nature of PHP. 
 +  * People who don't want to write script open tags don't have to write it at their own risks. 
 + 
 +==== Details ==== 
 + 
 +  * [[nophptags#​discussions|Discussion]] 
 +  * [[nophptags#​background|Background]]
  
 ===== Example Usage ===== ===== Example Usage =====
 +== Mode control and compatibility ==
  
-==== Mode control ====+NOTE: **This example assumes template_mode=on/off affects behavior of include()/​require(). This is open issue of this RFC.**
  
 Modern frameworks have single bootstrap script and template rendering function. Modern frameworks have single bootstrap script and template rendering function.
Line 70: Line 134:
  
 In template rendering function In template rendering function
 +<code php>
   function render_template($template,​ $template_vars) {   function render_template($template,​ $template_vars) {
-    ini_set('​template_mode',​ '​on); ​ // Older PHP ignores +    ini_set('​template_mode',​ 'on'); // Older PHP ignores 
-    // Do what ever required as template +    ​include($template,​ $template_vars); ​// Or use any other method to render. 
-    ini_set('​template_mode',​ '​off'​); ​ // Older PHP ignores+    ini_set('​template_mode',​ '​off'​);​ // Older PHP ignores
   }   }
 +</​code>​
  
-This piece of code work with/​without this RFC. It would not be affected by php.ini, since it works for both template_mode=on/​off. 
  
  
-===== Issues yet to be resolved =====+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().
  
-  * php.ini flag and CLI options are not implemented in the attached patch.+<​code ​php
 +  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);​ 
 +    } 
 +  } 
 +</​code>​
  
 ===== Patch ===== ===== Patch =====
 +
 +This is PoC patch that only controls template mode. No script()/​script_once() implementation.
  
 https://​gist.github.com/​2266652 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.
 +
 +<doodle title="​Introduce script()/​script_once()"​ auth="​yohgaki"​ voteType="​single"​ closed="​true">​
 +   * Yes
 +   * No
 +</​doodle>​
 +
 +Directly called script cannot use script()/​script_once(). Remove inconsistency between directly executed script and indirectly executed script.
 +
 +<doodle title="​Allow to omit script open tag for direct script execution"​ auth="​yohgaki"​ voteType="​single"​ closed="​true">​
 +   * Yes
 +   * No
 +</​doodle>​
 +
 +
 +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
  
  
Line 165: Line 272:
  
 The only looser is attacker here. If you think of drawback that exceeds these benefits, please let me know. yohgaki@ohgaki.net The only looser is attacker here. If you think of drawback that exceeds these benefits, please let me know. yohgaki@ohgaki.net
 +
 ==== What is compatibility issues? ==== ==== What is compatibility issues? ====
   * No new syntax or parameters. Only template_mode ini entry.   * No new syntax or parameters. Only template_mode ini entry.
Line 189: Line 297:
   * Common protections   * Common protections
     * **ALWAYS VALIDATE USER INPUTS** if the input is reasonable one or not. (Not only for LFI, but for general security)     * **ALWAYS VALIDATE USER INPUTS** if the input is reasonable one or not. (Not only for LFI, but for general security)
-      * validate ​parameters contains only valid chars. (i.e. no "​../"​ Use white list chars, not black list.) +      * Validate ​parameters contains only valid chars. (i.e. no "​../"​ Use white list chars, not black list.) 
-      * validate ​parameters are not too long. (i.e. file names would not be too long such as "​valid/​path/​../​../​../​../​../​../​../​etc/​passwd"​)+      * Validate ​parameters are not too long. (i.e. file names would not be too long such as "​valid/​path/​../​../​../​../​../​../​../​etc/​passwd"​)
       * For example: if (strspn($filename,​ '​01234567890ABCDEF'​) != 32) die('​Invalid file name as MD5 sum');       * For example: if (strspn($filename,​ '​01234567890ABCDEF'​) != 32) die('​Invalid file name as MD5 sum');
       * Avoid regular expression as much as possible.       * Avoid regular expression as much as possible.
       * Never use ereg() to validate. ​       * Never use ereg() to validate. ​
         * Not binary safe and its line oriented = Can't be used for validation.         * Not binary safe and its line oriented = Can't be used for validation.
-    * always ​add file extension manually for include()/​require()/​include_once()/​require_once(). ​+    * Always ​add file extension manually for include()/​require()/​include_once()/​require_once(). ​
       * Use null byte protection! Null byte protection requires 5.3.4 or later.       * Use null byte protection! Null byte protection requires 5.3.4 or later.
       * For example: include($module_name.'​.php'​);​ This makes only "​.php"​ files can be read by include() with recent PHP.       * For example: include($module_name.'​.php'​);​ This makes only "​.php"​ files can be read by include() with recent PHP.
       * If you are using PHP 5.3.3 or less, null byte protection is not available. You **MUST** make sure strings are not contains null bytes.       * If you are using PHP 5.3.3 or less, null byte protection is not available. You **MUST** make sure strings are not contains null bytes.
-    * add safe prefix for include()/​require()/​include_once()/​require_once().+    * Add safe prefix for include()/​require()/​include_once()/​require_once().
       * This protects against absolute path attack.       * This protects against absolute path attack.
       * For example: include('/​my/​base/​path/'​.$module_name.'​.php'​);​       * For example: include('/​my/​base/​path/'​.$module_name.'​.php'​);​
-    * validate ​data file. +    * Validate ​data file. 
       * It would not help much without this RFC, but it should be done anyway.       * It would not help much without this RFC, but it should be done anyway.
       * Check MIME types by mime extension at least.       * Check MIME types by mime extension at least.
       * Check data file has proper headers.       * Check data file has proper headers.
       * For free format data files, add your own header.       * For free format data files, add your own header.
-    * if you are using Unicode Normalization,​ you must know what you are doing. +    * If you are using Unicode Normalization,​ you must know what you are doing. 
-      * always ​normalize first, then validate. +      * Always ​normalize first, then validate. 
-    * use open_basedir ini option to reduece damage when there is LFI. +    * Use open_basedir ini option to reduece damage when there is LFI. 
-    * do not disclose your system information.+    * Do not disclose your system information.
       * Do not write error that contains path or anything that may help attackers.       * Do not write error that contains path or anything that may help attackers.
-    * be protective+    * Be protective
       * Enable all errors.       * Enable all errors.
       * Write code that will raise no errors/​exceptions for normal execution.       * Write code that will raise no errors/​exceptions for normal execution.
Line 231: Line 339:
       * Location to be inserted depends on data file, but data file has reserved area. Inject <?php die()?> into the area.       * Location to be inserted depends on data file, but data file has reserved area. Inject <?php die()?> into the area.
     * Previous requirement is almost impossible to enforce, since PHP may read any file with permission. (e.g. inserting <?php die()?> in /etc/passwd is possible, but it is not feasible obviously. )     * Previous requirement is almost impossible to enforce, since PHP may read any file with permission. (e.g. inserting <?php die()?> in /etc/passwd is possible, but it is not feasible obviously. )
-    * consider ​template_mode=off,​ since embedded mode is dangerous by its nature.+    * Consider ​template_mode=off,​ since embedded mode is dangerous by its nature.
  
   * When **template_mode=off** in php.ini or bootstrap script,   * When **template_mode=off** in php.ini or bootstrap script,
-    * enable ​template_mode only when it is absolutely required.  +    * 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.+    * 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.     * Note: When template_mode=off,​ even if programmer dropped all protections,​ LFI would result in syntax errors in most cases.
  
Line 270: Line 378:
       * PHP scripts that aren't be accessed by users should be located other than docroot. This is good practice without this RFC also.       * 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.       * 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 ===== ===== Background =====
Line 357: Line 470:
  
 Note: open_basedir will not be set by default. Note: open_basedir will not be set by default.
- 
  
  
Line 367: Line 479:
    - 2012-04-11 Yasuo Ohgaki: Version 1.3. Reorganized sections and sentences.    - 2012-04-11 Yasuo Ohgaki: Version 1.3. Reorganized sections and sentences.
    - 2012-04-12 Yasuo Ohgaki: Version 1.4. Simplified summary. Reorganized sections and sentences.    - 2012-04-12 Yasuo Ohgaki: Version 1.4. Simplified summary. Reorganized sections and sentences.
-   ​- ​+   ​- ​2012-04-16 Yasuo Ohgaki: Version 1.4. Added ENV var switch and script()/​script_once().
rfc/nophptags.1334191864.txt.gz · Last modified: 2012/04/12 02:51 by yohgaki