interpolation proposals and safety

Steven Schveighoffer schveiguy at gmail.com
Fri Aug 30 14:36:56 UTC 2024


On Friday, 30 August 2024 at 12:07:47 UTC, kdevel wrote:
> On Thursday, 29 August 2024 at 14:21:24 UTC, Steven 
> Schveighoffer wrote:
>> On Thursday, 22 August 2024 at 19:34:32 UTC, kdevel wrote:
>>> `writeln` should not print unadorned interpolated string 
>>> expressions.
>>
>> I find this argument unconvincing.
>>
>> You can print anything with `writeln`. [...]
>
> Not really, e.g. in the case of an object the class name will 
> be printed instead of the potentially dangerous content:
>
> ```
> import std.stdio;
>
> class C {
>    string s;
>    this (string s)
>    {
>       this.s = s;
>    }
> }
>
> void main ()
> {
>    auto c = new C ("<script>alert(-1)</script>");
>    writeln (c);
> }
> ```

But it still prints something. I guarantee if someone could have 
figured out how to make it print all the fields via a runtime 
interface, this would have happened.

In other words, the *expectation* is that the `toString` value is 
useful for string representation logging by default. The class 
name is the best you can do with a runtime-only interface by 
default, so that's what it is. It wasn't a conscious choice with 
HTML injection in mind.

> In a superior implementation of write(ln) this would simply 
> also not compile. I mean there is a difference between printing 
> the data payload to the output channel and OTOH dumping debug 
> information to the developer.

If `Object.toString()` didn't exist, then `writeln(someObject)` 
would by default print the class name via 
`typeid(someObject).toString()`. There is no chance this would be 
an error by default.

>
>> The point of making IES play nice with `writeln` is that it is 
>> a major expectation of any kind of interpolation setup. People 
>> just expect to log interpolated sequences that have their 
>> stuff in it.
>
> I don't know if you noticed your own wording: We are expecting 
> to "log" IES data but not to "print" them to the output channel.

Yes, I purposely said log, because that's the intention of 
`writeln`. It's logging the most useful data to the console. For 
structs, this is all the fields, and the struct name.

For IES, this is what it does for string representation, because 
that's what people would expect. Use any other language with 
interpolation, and you will find it does the same thing when 
logging. Can you imagine what the blowback would be if 
`writeln(i"hello $(name)!");` was an error?

If anything, this draws attention to the pitfalls of CGI in 
general.

For instance, what if you call a function that logs something to 
the console? That gets included in your html.

>> [SQL]
>>
>> Basically, you found just a very narrow example that is 
>> unlikely to exist, but indeed might be confusing if an exact 
>> series of mistakes are made. Even without IES, a user is 
>> equally likely to use `writef` to make the same mistake.
>
> With post-1036e D the user has now three equally potent ways to 
> shoot theirself in the foot:
>
> 1.
> ```
>      data = "alert (-1)";
>      writeln ("<script>" ~ data ~ "</script>");
> ```
>
> 2.
> ```
>      data = "alert (-1)";
>      writeln (format!"<script>%s</script>" (data));
> ```
>
> 3.
> ```
>      data = "alert (-1)";
>      writeln (i"<script>$(data)</script>");
> ```

4.
```d
writefln("<script>%s</script>", data);
```

When you have a footgun cabinet that is almost full, I'm not sure 
adding one more is something to worry about.

-Steve


More information about the Digitalmars-d mailing list