I don't consider this to be a good defence; in fact, I'd argue that makes PHP itself insecure.
I like to think of secure coding in terms of the 'path of least resistance' for a lazy/busy/inexperienced developer. If doing things securely makes life harder, things will be done insecurely.
We don't need to make the secure approach easier in absolute terms; we can just make the insecure approaches more painful. In this case: have database functions require arguments of an 'SQL' type, rather than strings; make it easy to write literal SQL values; make it easy to parameterise SQL values; make it as hard as possible to convert a string value to an SQL value, e.g. bury it in some deep namespace hierarchy, with a long and scary-sounding name, require a config value to be enabled (or even make it a compiler flag!), etc.
This way, the docs (plus stack overflow, blog posts, etc.) don't have to choose between showing a secure approach or showing the simplest approach; since they are the same!
It usually is easy to parameterize things like values used in WHERE clauses. It's often much harder to work with dynamic query conditions (e.g. optional filters on a particular column). I don't believe I've seen an approach that does this in a way that can provably provide any sort of safety guarantee.
- SQL logic. We should be able to write this as a literal query, parameterised as needed, e.g. (made up syntax)
query(
addParam(
"MyParam",
$myParam,
SQL"SELECT foo FROM tbl WHERE @MyParam IS NULL OR bar = @MyParam"
)
)
- PHP logic. This is just ordinary control flow, like anything else, e.g.
query(
($myParam === null)
? SQL"SELECT foo FROM tbl"
: addParam("MyParam", $myParam, SQL"SELECT foo FROM tbl WHERE bar = @MyParam")
)
- A mixture of SQL logic and PHP logic. This seems inherently unsafe to me, so it's not surprising that safety guarantees can't be proven. My point is that such things should be be made difficult ("artificially", if needed), such that nobody would choose to go down that route when another option is available.One approach would be to construct a list of conditions as well as a list of parameters to be substituted. Shown below without any particular language syntax, but hopefully comprehensible.
conditions = ("foo=?", "bar>?") parameters = (fooValue, barValue)
Then when building the SQL, you join the conditions together with AND and substitute in the parameters. This works in the sense that you are still prevented from injection. But it's rather messy. I suppose perhaps you can actually do what I'm discussing with some ORMs in a reasonably clean way. But my point is that most SQL interfaces make it easy to parameterize a single set of fixed values, but hard to do so for table and column names. Arguably this is a feature not a bug since you probably want to avoid such parameterization anyway. But having a safer way to do so would be nice.
Agree with you completely on that. PHP, is in fact, insecure by design.
That's exactly why tools and languages should be designed for security, so that their users don't have to care.
I also disagree about 'not caring about security at all': security is opposite to functionality, since it prevents things rather than enabling them. If developers truly didn't care about security, we would see far more use of 'eval' as a way to plug systems together. Instead, we see a huge amount of effort spent on defining data and interchange formats, parsing parameters, branching on their values, etc.
For example, any time an API/URL provides options like '?sortField=age&sortDirection=DESC', that indicates developers who do care about security. In contrast, we can make a far more flexible API by accepting arbitrary code instead, like '?postProcess=(x) => x.sortBy((elem) => elem.age).reverse'; and this is much easier to implement, since we could just send it to 'eval()'.
I have to wonder: what did these people have to gain if PHP got popular (which it did)? That's an egotistical way of popularizing your language.
So not sure what you're trying to push here but I refuse to participate.
If it was about accessibility, they should have made an easy installer and even offered cheap hosting themselves I think.
As for SQL injection, were prepared statements even a thing back then? Either way they should never have allowed and normalized string concatenation to build up SQL queries.
Mysqli driver was released with PHP 5.0 in 2004, it has prepared statements.
Hah, that was one of the biggest strength of PHP stack - it was not complicated; on you MS Windows machine it was enough to install some wammp/xammp, etc. PHP/MySQL/Apache bundle, open editor, put in the first line <? and start coding.
On production, typically some shared hosting (cheap! Another said stack advantage) this was already installed, so it was sufficient to FTP files over there and be done (one more advantage).
There was no other comparable stack in terms on simplicity and being able to do something quickly. I believe there is none today, only PHP stack matured, so there are frameworks, etc.
Yes, there were security concerns, but still much less comparing to its server-side predecessor CGI scripts (better known today as AWS lambdas or "serverless").
wow.
yes, prepared statements have been a thing since there were relational databases.
but also, (server side) prepared statements are not required in order to use SQL with bound parameters. the binding can occur just as easily on the client side, and this is in fact quite common. the point is that the programmer is not manually deciding whether or not to escape a parameter on a query-by-query basis, the process is automated.
Yes. I was writing prepared statements in Perl before PHP3 was released.