Re: [RFC] is_trusted - was is_literal
| From: | Rowan Tommins | Date: | Wed, 23 Jun 2021 11:19:35 +0000 |
| Subject: | Re: [RFC] is_trusted - was is_literal | ||
| References: | 1 2 3 4 5 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-115058@lists.php.net to get a copy of this message | ||
On 22 June 2021 10:09:50 BST, Mike Schinkel <mike@newclarity.net> wrote:
>For my inspiration take a look at Trusted Types API in Javascript:
>
>https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API
><https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API>
There is an extremely important difference here: there is no single type in that system called
"TrustedString", there are separate types for each context ("injection sink").
The W3C article calls this out explicitly:
> Note: This allows the authors to specify the intention when creating a given value, and the
> user agents to introduce checks based on the type of such value to preserve the authors'
> intent. For example, if authors intend a value to be used as an HTML snippet, an attempt to load a
> script from that value would fail.
This is not just an implementation detail, it's an absolutely essential part of the concept.
So let me add my name to the chorus saying that is_trusted() is a bad name, and the added features
that led to its selection make this feature worse not better.
Most of a "trusted types" implementation can be written in pure PHP, because all you need
is an object with a private string property and some appropriate constructors.
The one part you can't do is trust strings provided in source differently from strings provided
by the user, and the original proposal provided a straightforward mechanism for that purpose.
There is no reason why is_literal itself needs to know about "trusted value objects", or
have a long list of special cases to construct a string that is "not actually a literal but we
can't think of any way to exploit it". That can all be handled by the userland code:
* Create a class called TrustedSql
* Accept a parameter of type string|TrustedSql. If the parameter is a string, reject it if
is_literal returns false
* Or, if a pseudo-type is provided as well, just accept literal_string|TrustedSql
* If the user wants to provide dynamic SQL, they need to construct a TrustedSql object using
whatever mechanism the library wants to provide. That can include an audited sprintf pattern,
imploding arrays of integers, whatever turns out to be useful.
I think the engine should leave the complexities of defining "trusted" to APIs
specialising in a particular "injection sink", and provide the low-level building block
they need, which is the original simple is_literal function.
Regards,
--
Rowan Tommins
[IMSoP]