Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:84065 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 39314 invoked from network); 28 Feb 2015 02:48:01 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 28 Feb 2015 02:48:01 -0000 Authentication-Results: pb1.pair.com smtp.mail=yohgaki@gmail.com; spf=pass; sender-id=pass Authentication-Results: pb1.pair.com header.from=yohgaki@gmail.com; sender-id=pass Received-SPF: pass (pb1.pair.com: domain gmail.com designates 209.85.192.46 as permitted sender) X-PHP-List-Original-Sender: yohgaki@gmail.com X-Host-Fingerprint: 209.85.192.46 mail-qg0-f46.google.com Received: from [209.85.192.46] ([209.85.192.46:54352] helo=mail-qg0-f46.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id FF/22-32582-F5C21F45 for ; Fri, 27 Feb 2015 21:48:00 -0500 Received: by mail-qg0-f46.google.com with SMTP id z107so17229842qgd.5 for ; Fri, 27 Feb 2015 18:47:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:sender:in-reply-to:references:from:date:message-id :subject:to:cc:content-type; bh=RI82FFKtg4/qpCGs3IUZ3ZIUf+R6afCE46X72t1j+68=; b=JyuK3HaM5R4+ybzqB0RCZISDrKDb3qtwpko5Usd8L88zTX7wBuzTUrN6C824T96oo+ B0fVPWkQxzxsGMayoeBccM+T14M7WFx5QIQTU71aqjmT/ZaQMX45yAHbvqRkXK/DkCR0 ChObHMBBCdx8WZfG/SozkZ0hX3ses02QtehdmEBygfVTSr1iApktxJtua6v1O+YKr0kL HjzpQND789EVhACYV2IHjk9q+/oG7kirroWCuqv20iLDO1uwSzUUeYhuFVoCNsZhpp75 mM4BDPFaOiFBmFhSYtnjUemOq2Pi5U10a8UDojZ067ZneSAJIwbZdY0N3XImAA8NGn6Y 0M3A== X-Received: by 10.140.151.8 with SMTP id 8mr34684824qhx.65.1425091676361; Fri, 27 Feb 2015 18:47:56 -0800 (PST) MIME-Version: 1.0 Sender: yohgaki@gmail.com Received: by 10.229.198.8 with HTTP; Fri, 27 Feb 2015 18:47:15 -0800 (PST) In-Reply-To: References: <54F0540C.1040807@gmail.com> Date: Sat, 28 Feb 2015 11:47:15 +0900 X-Google-Sender-Auth: Dqoq09WlwxAFfCLr6_K-uFNr86s Message-ID: To: Rowan Collins Cc: "internals@lists.php.net" Content-Type: multipart/alternative; boundary=001a11353862245cd005101d03fa Subject: Re: [PHP-DEV] [RFC][DISCUSSION] Remove allow_url_include INI From: yohgaki@ohgaki.net (Yasuo Ohgaki) --001a11353862245cd005101d03fa Content-Type: text/plain; charset=UTF-8 Hi all, On Sat, Feb 28, 2015 at 11:37 AM, Yasuo Ohgaki wrote: > On Fri, Feb 27, 2015 at 8:25 PM, Rowan Collins > wrote: > >> Yasuo Ohgaki wrote on 27/02/2015 03:44: >> >>> Hi all, >>> >>> This is RFC for removing "allow_url_include" INI option. [1] >>> >>> During "Script only include" RFC[2] discussion, stream wrapper issue is >>> raised. >>> I was thinking this issue as a separate issue, but it seems others are >>> not. >>> >> >> I'm not convinced by the argument that because "phar://blah" looks like a >> URL, allowing it makes allow_url_include broken. Perhaps it would be better >> named allow_remote_include, but it corresponds to masking out your >> PHP_STREAM_REMOTE flag further down, which is the more important >> protection. If you want to be able to disable phar:// access, you could add >> something like allow_local_stream_include for that case without breaking BC. >> > > allow_local_stream_include is one possible solution. It has the same > problem with allow_url_include. > Since allor_url_include is global INI, it applies to child scripts. e.g. > > A.php > ----- > ini_set('allow_url_include', 'On'); > include('B.php'); > ----- > > B.php > ----- > include($_GET['var']); // Not only local script execution vulnerable, but > also remote script execution is possible because "allow_url_include=On" > here. > ----- > > We need to control these flags more precisely. That's the reason why I > proposed 2nd parameter for include. > If flags are globals, we cannot control them as it should. > > URL and URI is the same for most users, I think. (It differs, but their > usage is mostly the same) Not > many users expect to work something like > > > include('new_wrapper://some_file_with_special_content/some_how_php_script_is_accecible_suddenly'); > > Attackers can write malicious user stream wrapper as back door. Then > upload attack file and takeover > server. The wrapper will be hard to distinguish if it's legitimate or not. > Attack file can be any kind of > format. It's impossible to detect as malicious file. URL formed script > (stream wrapper) is very flexible/handy/ > hard to be detected tool for attackers. > > Remote resource is extremely danger. Local resource is very dangerous > also. Current phar:// wrapper > implementation spoils file extension and ".." (double dot) protection that > is deployed by many PHP codes > already. User wrapper seems allowed for include(), so malicious user > wrapper can help attackers to > exploit PHP servers. > > > I'm also not at all clear what you mean by "caller" and "callee" >> responsibilities; surely the difference is just between a global option >> (ini_set()) and a local one (extra argument)? And in what way does Option >> #2 require more changes than Option #1, since they both require the >> argument to be present whenever a stream wrapper is used? >> > > First question is answered in previous comment. INI cannot control flags > precisely... > > Option #1 is simple string comparison for filename is passed. It does not > care what's the filter at all nor even filter name is valid or not. 2nd > parameter is > used to make sure filename passed to include() is user's intension. e.g. > > ----- > // somewhere deep in code > $module_name = substr($_GET['module'], -4, 4) === '.php' ? > $_GET['module'] : ''; // Do not care to much, we have safe .php files. > > // somewhere far from above code > include($module_name); // phar://evil_phar/evil_script.php can be executed. > ----- > > With this RFC, if 2nd parameter is omitted > > ------ > include($module_name); // E_RROR, URL formed include(stream wrapper) is > not allowed. > ------ > > to use phar. User must be explicit. > > ----- > include($module_name, 'phar://'); > ----- > > Option #2 will be much more complex than Option #1, since it introduces > types of wrapper, force users to have class method return wrapper type and > pass flags around functions to handle wrapper types correctly. There may be > more. > > > I do think local options are better than global ini settings in many >> cases, but include/require/etc are statements, not functions, so giving >> them extra arguments is awkward - some of your examples are "wrong" in this >> regard: >> >> // Redundant brackets make this look like a function, but it's not: >> include('phar://phar_file/script.php'); >> > // I can add as many as I like, the parser is just resolving them to a >> single string expression: >> include(((('phar://phar_file/script.php')))); >> // This is the actual syntax: >> include'phar://phar_file/script.php'; >> // Implying this for arguments: >> include'phar://phar_file/script.php', 'phar://'; >> // You could explicitly allow a "function form" of the statements, so you >> could parse this: >> include(('phar://phar_file/' . $script_name), 'phar://'); >> // But then you've got a subtle BC break, because the interpretation of >> this changes: >> include ($foo) . ('.php'); >> > > I used include('phar://phar_file/script.php'), but it can be include > 'phar://phar_file/script.php'. > I'm using () since it seemed harder to distinguish parameters and other > text as we can > use () for include/require now. > > I have no intention to change current include/require syntax, except > adding 2nd parameter. > > Thank you for your feedback. I hope I explained well enough. > I'm thinking merging this RFC to "Script only include" RFC. I have to > start over, but it seems > I must do this. > > I'll use Option #1 since it's much easier/simpler/less BC/more precise. > However, > ideas are appreciated always. > In short, I'm saying we have serious security problem in our current stream wrapper implementation and it's friends including include/require. Regards, -- Yasuo Ohgaki yohgaki@ohgaki.net --001a11353862245cd005101d03fa--