Hacker News new | past | comments | ask | show | jobs | submit login

I would suggest at least two important mechanisms at work.

First, template libraries have a fundamental drive towards power. A lot of people will talk big about separating the data from the template, but my gosh it's convenient to put for loops in your template, and be able to resolve properties, and before you know it, one feature at a time, your template code is basically as powerful as your local reflection capabilities. Sometimes, as may have happened here, even the people implementing these powerful features do not know how powerful they are. So there's this powerful pull on template libraries to become more and more powerful.

But they're usually written from an assumption of the user of the template having full control over the contents and that nobody is maliciously feeding content to it. It's an assumption that template libraries often start with, as an unspoken and unexamined assumption. Unbeknownst to the template library author, someone out in the world turns out to want templates, because they're so useful and convenient, and the person picking the template library may never consider whether or not the template library they are using matches the security profile they need, because quite often literally nobody at any point of this process is really thinking about that. So it's really easy for someone to grab a templating library that is way too powerful. They're likely to even consider "way too powerful" as a feature.

Second, there is a common mistake made in reflection-type APIs shared by many dynamic languages (dynamic languages have their "reflection-type APIs" simply built in, static languages usually have a library/module/package), and also in this case, Java, whereby there is some API to take some sort of string that identifies a class, and get an instance of it, or whatever the local equivalent is. Unfortunately, this turns anything that can invoke this functionality into arbitrary function execution, and "arbitrary function execution" is often leveragable into "arbitrary code execution" with only a bit more work. Again, this is done because it's really convenient and powerful, but it also means there's this Magic Portal in your language where if something can reach out to that functionality, then it can reach anything in the runtime, or possibly beyond if code can be loaded (which it usually can).

These two things, when combined, create devastating security bugs. Relatedly, overaggressive deserializers can also serve as your gateway into reflection ("my gosh it's convenient to be able to name arbitrary classes and deserialize into instance of them"), which is what Ruby had with its YAML arbitrary code execution a few years back. The combination of "some way into the reflection system" and "a reflection system that allows access to all classes in the system" is deadly.

Taking it one "why" further down, I think developers do not in general understand the interplay between "power" and "restrictions". There's a lot of developers who, given the choice, will always choose power, but in a multi-user world, that means you lose out on some very useful restrictions. A "power programmer" may chafe if they have to work in Go or C or C++ or some other language that doesn't have the built-in "name a class with a string, get an instance" functionality, but having that restriction around turns out to be very useful.

When you add more "power" to anything, you should always flip the question around and consider it from the dual perspective of "what restrictions am I losing in order to obtain this power?" Sometimes it will be nothing you care about, and in that case, go for the power by all means. But sometimes, deliberately putting down the "power" to simply name a class and get an instance means you're putting in a very, very useful guard rail.

(If you think about it, there's almost never a situation where you need to name an arbitrary class. You can almost always instead force some sort of manual registry of such things. Even cases you might think otherwise like "interpreters" you could probably still force manual registration of allowed classes. Only a very privileged interpreter that is very trusted could be allowed to have that power and lose that restriction.)

It is really easy to lose track, in all these moving pieces, of the fact that you've given away too much power.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: