Re: [Concept] Flip relative function lookup order (global, then local)

From: Date: Wed, 21 Aug 2024 12:03:57 +0000
Subject: Re: [Concept] Flip relative function lookup order (global, then local)
References: 1 2  Groups: php.internals 
Request: Send a blank email to [email protected] to get a copy of this message


On Wed, Aug 21, 2024, at 10:23, John Coggeshall wrote:
> 
> 
> On Aug 2 2024, at 4:37 pm, Bilge <[email protected]> wrote:
>> My only concern is there needs to be an alternative way to do this: intercepting internal
>> calls. Sometimes, whether due to poor architecture or otherwise, we just need to be able to replace
>> an internal function call. One example I can think of recently is where I had to replace
>> header() with a void function in tests, just to stop some legacy code emitting headers
>> before the main framework kicked in, then unable to emit its own response because HTTP headers had
>> already been sent. In a perfect world it shouldn't be necessary, but sometimes it is, so I
>> think for this proposal to be palpable there must still be a way to achieve this.
> 
> Just a tangent thought to the above, but I've always been a little concerned with the idea
> that a malicious composer package could potentially do nasty things because PHP looks at the local
> namespace first for functions. For example, if a composer package focused on Laravel that defines
> malicious versions of internal functions for common namespaces like App\Models ,
> App\Http\Controllers , etc. it could do some nasty stuff -- and supply-chain attacks
> aren't exactly uncommon.  Even worse is Wordpress or any other PHP-based software package that
> allows arbitrary plugins to be installed by non-technical users who really would have no idea if the
> package was safe even if they were looking at the code.
> 
> <?php
> // something.php
> namespace App\Models;
> 
> function password_hash(string $password, string|int|null $algo, array $options = []): string
> {
>    print("Hello");
>    return $password;
> }
> 
> <?php
> // my code
> namespace App\Models;
> 
> include "something.php";
> 
> password_hash('foobar', PASSWORD_DEFAULT);

If this is an attack vector for your application, then fully qualified names is the way to go
(WordPress does this nearly everywhere, for example).

> 
> I don't recall why local namespace first won, but IMO it wasn't a great call out the
> gate for that reason alone.  Yes, you can always use \password_hash  instead of
> password_hash , but making the default insecure and slower is silly IMO -- and not
> fixing it because of BC seems like the weaker argument here.
> 
> John

It's not (at least for me) the BC break. It's being able to override global functions.
There are legitimate use-cases outside of testing. For example, consider when a global function
signature changes. In your library, you have to check the php version. You can change this 100 times
for every single call, or you can just wrap it in a function that supports the old signature and
proxies it to the new signature. In other words, it provides options that may be better than the
alternative.

— Rob


Thread (112 messages)

« previous php.internals (#125090) next »