Google results for PHP tutorials contain SQL injection vulnerabilities
waritschlager.de
waritschlager.de
This isn't new, we've always had programmers who programmed by "recipe" rather than first principles, and DRY paints that as a feature, but it underlies a lot of pain and cost over the years.
To give some context, I inherited some kernel code when I worked in the Systems Group at Sun Microsystems in the 80's that was written by a mathematician who had become a programmer because the money was in programming, not applied math. They had cut and pasted code they didn't understand in order to achieve the result they wanted out of the code they were "writing." When I inherited it I read through it and found a couple of dozen ways the code would panic the kernel[1]. Once fixing those obvious issues, it became clear that the original owner of the code didn't really understand what computation did. They had an idea, and mathematically they could show that it was correct, but literally no ability to express that algorithmically.
This is not a "new" problem but it is an important one that managers of software engineers need to watch for.
[1] At the time the only difference between "kernel" programmers and "application" programmers was that kernel programmers recognized that unsafe code crashed the whole system, not just the application. So they tended to be cultivated from paranoid programmers.
None of these answers seem to come from SE so this might be harder than you might assume.
I'd love to see a concrete example of this happening in this way!
The rest of your story just describes 'smart, but bad jr. programmer' and doesn't really discuss the exploit issue.
There was a really good post on how to do it and evade detection.
PHP has been in a poor shape for many, many years. It started shaping up in last rather few years, and there is a large backlog to tackle, colossal if you include all the numerous tutorials and Q&As from getting copy-pasted since 2000.
The problem always was the ecosystem that took decades to update and the fact that Google's search is algorithm-ranked and not supposed to be curated by humans, which would have kicked out at least the most horribly insecure stuff.
sql_query($db,$sql,$params);
Problem solved.
I guess every PHP developer writes a bunch of these wrapper functions for common sql tasks before he starts his work.
At the cost of some performance, but the ease-of-use with a highly-tested and relied-upon library normally outweighs that.
Is PHP supposed to be a high-level language or what? Hell, I'd consider it a very flimsy excuse even in C (in most contexts anyway).
$stmt = $pdo->prepare('INSERT INTO user (email) VALUES(?)');
$stmt->execute([$email]);
https://news.ycombinator.com/item?id=27954454I wouldn't call it a language failure per se, but a problem with the libraries that shipped with the language. That distinction may not make a difference.
Bad examples that stuck around don't help either, of course.
Is your contention that Google is to blame for indexing them?
I no longer consider myself part of the PHP community (started around 1999), in part due to the low priority reliability and security had. It was exhausting having to vet code so frequently because even experienced developers forgot all of the rakes in the grass.
This is still to this day the recommended way to construct a "WHERE foo IN (a,b,c,...)" query in PHP. It's insane that there's no way to pass an array of values into a parameterised query for that use case.
There's no way of doing this with a single parameter. You need to parameterise every single individual item in the IN clause to do it that way, which is a horrific solution when it's of a completely unknown length.
Still better than string concatenation in many cases, but that the language has no in-built way of doing it is one of the many reasons PHP code is so often vulnerable to injection attacks. There's so much friction to writing secure code.
$user_ids = [1, 6, 46, 3, 17];
$count = count($user_ids);
$in = '(' . implode(', ', array_fill(0, $count, '?')) . ')';
$sql = "SELECT user_id, email FROM user WHERE user_id IN {$in}";
$stmt = $pdo->prepare($sql);
$stmt->execute($user_ids);
var_dump($stmt->fetchAll());Unfortunately that gets people into the habit of using string concatenation, which is not a great habit to have.
I speculate that the reason this is such an issue is because the interface at the ODBC level is basically security wise broken. It works 'OK' for getting/putting the data but it has 2 modes of execution. One of those paths is not great for security, the other has a usage issue. 'Binding' can be a real pain as it takes at least 1 call per variable parameter. Then managing the buffers correctly. So just building up the strings is an easy way to skip a lot of steps. So many take it. But that path leads to security vulins.
This is somewhat the point. If using the language's standard libraries is "absolutely doing it wrong", that's an indictment of the language.
You are being deliberately obtuse. Other comments in this thread offer correct examples of using PDO to avoid SQL injection. I didn’t mean it was impossible to write safe database code using the standard library—obviously, PHP is a Turing-complete language, it can be done!—I just meant it’s awkward, and verbose, and developers are unlikely to do it consistently throughout an application. Hence this type of concern is best abstracted into a library.
To your point about “indicting a language,” most languages have footguns like this. The worst you can say about PHP is that the documentation should do more to discourage new users from working with PDO directly. (And I mean the official documentation—the language maintainers can’t be held responsible for the kind of unofficial tutorials the article complains about.) But regardless of what the official docs say, most PHP development today is done using frameworks like Laravel, Symfony, and Zend framework that do not suffer from SQL injection issues.
Exactly, all languages have footguns but some have a lot more than others. You don't hear for example Java developers bitching about JDBC to anywhere close to the extent PHP developers bitch about the various common approaches to database connections.
Common database drivers like PGSQL, MySQL, SQLite etc. don't accept arrays of values for parameterized queries. This is at C level, in their own client libraries, and their own communication protocols.
This means there's nothing specific to PHP about this problem. Many higher level libraries, including for PHP, abstract over this problem and do offer arrays by binding per query.
So where are statements like yours coming from? Probably just being eager to say something bad about PHP without checking your facts too much.
I don't particularly care if languages that I am not using have the same problem. It's up to people who use those languages to make those criticisms.
> Many higher level libraries, including for PHP, abstract over this problem and do offer arrays by binding per query.
Feel free to link an in-built PHP library that supports this feature, that would be far more useful than just obliquely suggesting that one exists.
> For example, you cannot bind multiple values to a single parameter in the IN() clause of an SQL statement.
You're required to roll your own implementation, something that thankfully isn't particularly difficult, but unfortunately also seems to be enough of a barrier that a lot of programmers don't bother.
Similarly, PDO doesn't support dynamic table names. You're expected to roll your own precisely because it demands more situationally specific escaping than regular parameters would, e.g. testing a list of allowed tables.
I just want to point out the above is identical to saying "is bad" without explaining why it's bad.
We can say it doesn't align with PDO's goal of being barebones library that doesn't add non-native features on top. But that's not what it does. It both omits many native features on the various databases it supports, and has non-native features like hydrating objects, for some reason.
I'd say if a PHP library is at the same level as the C library that backs it, that's a failure of design goals. C is intentionally low-level (by modern standards) and PHP is supposed to be high-level and consumable by people with much less clue than C programmers.
It's unfortunate that you pretty much need a DBAL (like Doctrine DBAL) on top of a DBAL (PDO) to get some of the missing features. Like, say, escaping identifiers.
Key to great APIs is battle tested APIs in real world projects, finetuned over years of experience. PHP has that in the much larger general PHP community and to access it you use composer.
We, the PHP community, must use all resources to compete with other languages, it is unrealistic that the core PHP team can implement a great API, for example we can look at the filter API, it works but it is not great. PHP core also has longer release cycles.
We need to push PHP developers to use composer more, maybe the PHP docs should state that.
https://www.php.net/manual/en/mysqli.quickstart.prepared-sta...
Of course at C level parameterised queries ("prepared statements") do not accept arrays. It would not make sense for them to do.
This is because the placeholders can be substituted by values of different types.
In typed programming languages, arrays have elements of the same type.
For example in SQLite, you are supposed to call `sqlite3_bind_int()`, `sqlite3_bind_text()` [1], once for each query parameter.
In languages like PHP and Python, where arrays can carry values of different types, their wrappers around the SQLite C functions can do this function calling for each value in the array. In Python, that is easy, the default, and explained in the very beginning of the official standard library's sqlite documentation [2]:
It states at the very beginning that query construction by string construction is unsafe and must be avoided. It immediately provides an example of how to safely call a parameterised query with an array of values, using `execute()` and `executemany()`.
PHP's standard library simply does not seem to have such an `execute()` function that accepts an array [3], nor do the official docs seem to contain any prose that could explain how to use the library safely [4]. The only way you can find out is by reading user-contributed comments on some specific functions in the function reference.
So Python's standard library provides safe functions, and immediately instructs the user how to use them. PHP's does not. Unclear to me how one can conclude that this isn't a PHP specific problem.
[1]: https://www.sqlite.org/c3ref/bind_blob.html
[2]: https://docs.python.org/3/library/sqlite3.html
"WHERE status in (...?)" and then ->execute($status_array)
But you can pass an array of parameters just fine (to individually bound input placeholders). It depends on which API you're using but it's of the format: ->bind_param($types, ...$params); or ->execute($params);You can concatenate a sql query just fine in Python anyway you want. Adding a sql injection is just as easy in Python, PHP, or lisp. Thus this is a choice. Nothing to do with a language. Language bashing is gross and spreads lies. And yes, you can bind an array of params in PHP.
I don't know how carefully you read what I said, if you misunderstood that this is a native library limitation (C level) of the actual database clients, and that most of the popular PHP libraries can bind arrays.
Anyway your point is true that lots of languages' client libraries and ORMs implement sql "parameters" by string substitution. That's still better than having the programmer do it himself, but not as good as it could be.
One workaround to that is passing the array as a string with some separator, deconstructing it into a temp table and then using that table as a array when it is part of a stored procedure.
It's fairly trivial to do this, but now you're potentially adding thousands of parameters per query in circumstances where the contents of the IN() are variable in count. This is not ideal for a number of reasons.
Additionally, a language should be designed such that the easiest possible way to do something is at least moderately secure. If you need to attach some boilerplate code on top of the standard libraries every single time you use them for it to be safe, then there is no reason for that boilerplate to not be in the standard libraries.
Maybe I'm misunderstanding you, but assuming $params is an array in the following code, isn't this passing an array into a parameterized query for that use case? (Edited to note this is literally an example from the PHP documentation, and not one of the squiffy comments.)
$place_holders = implode(',', array_fill(0, count($params), '?'));
$sth = $dbh->prepare("SELECT id, name FROM contacts WHERE id IN ($place_holders)");
$sth->execute($params);
In Python, using MySQLdb, I believe this would be something like place_holders = ','.join(['%s'] * len(params))
cursor.execute("DELETE FROM foo.bar WHERE baz IN (%s)" % place_holders,
tuple(params))
Which, while more succinct, seems to be functionally exactly the same thing. I don't see what PHP is doing that's "worse" here offhand.One could argue, "Yes, but a Python programmer would use SQLAlchemy," which is probably true, but then you need to let the PHP programmer use Doctrine or Eloquent.
Yes, I definitely should have been more specific there - what I'm referring to is passing it as one parameter, instead of potentially dozens or hundreds. There's a lot of ways to do this safely, but none of them are elegant. In the example presented here I believe it's the case that you can't do the ->execute($params) and bind some parameters explicitly, so if you had something like " AND status = ? AND due_date < ?" at the end of your query you have to chuck those variables into the same nondescript array.
I prefer the looped bindParam() method for this reason, but that has its own challenges. Firstly, it requires some boilerplate (not a big deal, but no-one likes writing boilerplate), and more pressingly it still has the issue where it actually is each individual element of the array being parameterised, and spams the ever-loving crap out of any debug outputs.
Obviously all of these issues are way less concerning than SQL injection vulnerabilities, but life would be so much easier if you could just do $sth->bindParam(1, $params); on a single question mark, and have that show up logically in things like debugDumpParams(). Even if you had to use special syntax to indicate when a parameter is expected to be an array, that would be a huge improvement.
I'm sure there's technical reasons why this is more difficult to implement than it would initially seem, but I've seen enough string-concatenated queries on StackOverflow from people who just give up on getting the parameterisation to play nicely that I believe it's worth the effort to make doing things right as frictionless as possible.
It's not exactly a dark corner, but at least there's red boxes all over the place.
Back in the 5.x early days it had disclaimers but clearly not enough to discourage people from keeping unsafe code in place.
Otherwise they would not be Turing complete.. but defaults/easiest route does matter very much in this case.
String insertQuery = "insert into student values('" + studentNo + "','" + studentName +"','"+ studentAddress + "','"+studentAge+"')";
int result = statement.executeUpdate(insertQuery);
https://www.onlinetutorialspoint.com/jdbc/jdbc-insert-progra...Result #5 on Google for: jdbc insert program example
And this one, #1 for "jdbc example variable where" on Google:
String query = "select LastModified from CacheTable where " + " URL.equals(url)";
https://stackoverflow.com/questions/2608376/specifying-a-var...PHP directly exposed the libmysqlclient C library. Any language that provides the ability to send a raw SQL query (hint: almost all of them) has documentation you can copy and paste to introduce an injection vulnerability.
You'll find injection vulnerable examples in the MySQL docs themselves: https://dev.mysql.com/doc/c-api/8.0/en/mysql-real-query.html
I can't find those examples, is there something in the mysql docs that I can copy and paste and be instantly vulnerable?
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.
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()'.
PHP has a very forgiving design; it makes it very easy to get any trash code up and running. It really is great for newbies to get their hands dirty. I look back fondly on that first job, but boy did I have to unlearn a lot of bad lessons from those days.
This is the “No true Scotsman” fallacy of programming. There are many people with plenty of experience who haven’t yet learned that lesson memorably and at least an order of magnitude more who know it but don’t exhaustively trace every data flow through the system and assume something already handled validation or escaping, being correct all but a fatal few times. With unsafe defaults an attacker only has to find a mistake once — you have to find them all.
You need to teach developers to always escape strings, even if we remove old and bad tutorials you still need to teach the devs about this issues, otherwise they will do the mistake with file names, or with parameters to shell commands. It might mean having to read a book and not reeling on Google and soon on AI to teach you to code or SQL.
That might not seem like a lot at first thought but it lowers the bug frequency enormously in the code I’ve looked at because you only need extreme caution in rare cases rather than every view. That means that when someone is busy, having a bad day, etc. they either have no problem or it’s a safe crash rather than an exploitable hole.
This are just old pages that bad search engine surface. IMO if you focus the actual lessons here are:
- developers are lazy, you need to fix that, there is no magic language that solves the issue though some fanboys will say that their favorite language is more idiot friendly.
- search engine and soon the AIs are stupid, let's try to encourage books or other quality materials. Recently I found a collegue that did not know that in JS the "addEventListener" function exists and you can use it to add more then 1 listener at a time, this person probably can put on his CV 5+ yearts JS experience and a few frameworks. Mayb e if we stop focusing on the "my language is cooler" we could find the actual problems.
Back in my starting years I was reading books to learn, there when you get to the SQL chapter you were explained all about SQL injection and related bugs and how to use prepared statements. With PHP you can block this dangerous functions (PHP is flexible and many stuff like "exec" is blocked in most hosting places, but the problem with newb developers remain, if we can agree about this real problem(IMO_ we can maybe address it. Sure, downranking bad tutorials would be a part of the solution, also Google should probably stop their shit where they put the solution directly on the search page and not forces you to actualy visit SO and see comments, limitations and alternatives, shame Google, you make software industry worse with your greed...
Meanwhile I would said okay, what does it actually do, where’s you copy it from, what did you change and why...
At this point he would just get mad at me. I'm sorry I don't want people cutting and paste code they don't understand and sticking it in our codebase.
A newb can also copy paste bad Python code, mess up some ORM clause and delete all your database.
But in this case oh PHP and MySQL even the worst dev shop uses a framework or library, so this article is probably affecting almost nobody that matters.
Probably the same reason they still send people to sites like Expert Exchange
Running Light without Overbyte
[0] https://arstechnica.com/staff/2018/11/first-encounter-comput...
You would just study the code samples found in those books.
That's not what DRY should be. Good developers should understand at least a couple of levels of abstraction underneath what they're writing in order to produce sensible code.
The idea of abstraction is that you only have to spend the afternoon/day/week (depending on the complexity that's being abstracted over) learning how everything comes together once, as opposed to spending that time to grok a slightly different version of the same complex system every time you read/write something new.
DRY should not introduce vulnerabilities. It avoids them by
1. reducing complexity and cognitive overhead
2. allowing you to fix your code in one place and propagate your fix throughout the codebase
Something tells me that exploiters love the programmers who attempt to build user authentication systems from first principles.
Do you have any actual evidence for that?
As Hanlon says, "never ascribe to malice that which is adequately explained by incompetence."
Incompetence explains this one fully for me.
No, it doesn't. Programming by recipe rather than building the recipe into a reusable abstraction is the exact opposite of DRY.
From my experience, algorithms are easy and the software engineering is hard.
What’s more, many, not all, but many of these algorithm scientists look down on their programmer counterparts. It’s these folks who end up making the algorithm successful for the company.
I develop bare metal code for special µC, but I would never imagine to build even a basic OS. This is work you spend your lifetime in. Of course if I could just copy the things from established OS things might look differently.
That said, I don't think the first steps in SQL should guard against SQL injection. That is a topic for later and only hides the main learning target. You can understand SQL perfectly by first principles and still cause your first program to allow for such injection. But that should be a different lesson at first. Being able to identify it as a danger also relies on the experience of others.
Anecdotally I see SQL injection vulnerabilities in about half the code I look at. It’s one type of problem among many other problems and vulnerabilities in code written by amateurs and often copy/pasted.
PHP programmers can find lots of resources online. Some of those are terrible, either very old or written by amateurs excited to show how they got something to work.
I have seen the same kind of thing with Java and Python, but the popularity of PHP means there’s a lot of junk info and examples online.
PHP has supported safe SQL and safe HTML for decades, but the programmer has to understand the problem and the solution.
C:\Windows\System32> sfc /scannow
... followed by "reinstall your operating system". OK so no harm done apart from rather a lot of downtime, assuming you can put it back together again. The number of times I see "disable your AV" still is frightening.I have a browser plugin that I discovered thanks to this parish called uBlacklist which you can use to try and clean up your search results by banning known bad sites from your results. social.microsoft.whatever was first ... 8)
I also note an awful lot of Linux related link farms and "blogs" with ads and cloned content from other sources have surfaced over the last few years. WordPress is another quagmire. I could go on but basically, search is very close to completely screwed (but not quite.)
The Sysadmin stock answer to nearly all problems is
shutdown /r /t 0
If that fails, then sfc /scannowNow, if disabling works you should set reasonable exclusions and enable the product again.
Hopefully you choose wisely on what to install on your system. Hopefully you even know what is "wise" to install on your system.
If you find out what is wise to use on your system, please let us know.
I read the logs and set exclusions until the damn thing works. I have briefly disabled the whole AV/firewall/browser plugin thing sometimes to double check but that is quite rare. When I smile my teeth make a "ping" sound and briefly flash white.
Raspberry Pi tips is another quagmire of replicated garbage.
I wrote an article about this back in 2007, regarding Javascript examples in an O'Reilly book -- a source I used to recommend because of the quality of their writing and editing (I no longer have that opinion).
https://typicalprogrammer.com/learning-by-example-how-bad-co...
I started programming on MSX-BASIC (kind of like C64), and when we finally got a PC in 2000 or so I got a book titled "Learn C++ in 10 minutes". It was so bad hat I was turned off from programming for a few years, as I thought I just didn't have what it takes (it also didn't help that the tooling and "getting started" was much harder back then, especially on Windows; if I had known you could just download e.g. Python instead of mucking about with this pirated Visual Studio I probably would have had an easier time – but I didn't know about that. It wasn't until I started playing with FreeBSD a few years later that I got back in to programming).
* procmon, if you're lucky you'll catch WTF is going on somewhere deep in the registry
* Hoping Microsoft still has the answer in a KB article somewhere (hope you didn't need any Server 2008/2012 stuff that was on UserVoice, it's gone now)
* WinDBG if you're that good
Which brings us back to cargo culted answers like sfc /scannow
I wouldn't compeltely discount social.microsoft, very very occasionally it's had a tiny tidbit of information in between the people incorrecting each other.
With some knowledge and experience it's possible to fix a lot of problems. Actually, a lot of problems people chuck up to "Micro$ucks bad" are just hardware problems. If someone comes in with "I get random BSODs" then there's a good chance it's just faulty a faulty RAM module, disk, or something like that. The first step for random issues should always be to run memtest and a disk check tool (I don't recall the name of the tool I used for that, but there are some subtleties involved in testing this well, and I don't know the status of SSDs as this was kind of before they became common). Checking hardware is easy, checking software isn't.
Software problems can be a bit trickier to solve, depending on what the issue is. They're very hard to debug remotely over the internet: but there's a lot more you can do than "sfc /scannow" if you're sitting in front of the computer.
You really don't need WinDBG in most cases.
That's not good enough for a language advertising as "Hypertext Preprocessor" though. PHP's distinguishing feature is that's kicked off from SGMLish processing instructions in otherwise static HTML, and it has all context available for perfect injection-free HTML-aware templating. Eg escaping quotes when it's outputting into attributes, escaping "]]>" when outputting into CDATA sections, or with the help of a real markup processor, suppressing/escaping <script> elements or onclick or other event handler attributes where advised through a grammar such as an SGML DTD. But it doesn't because it's just such a hack job of a language, by the developer's own admission.
And, like with razor, you can use plenty of libraries with PHP that will encode by default.
There are various constructs in the language rarely seen in PHP code that make this easier, such as <?=, but also also "if (..):" which can be ended with "endif", and "foreach (...):" which can be ended with "endforeach".
It's not a hard feature to add. PHP devs want to move away from this "PHP as a template language" (I think they tried to remove the <?= a few years back); that's all fine, but fact of the matter is that people ARE using it as a template language and will continue to do so in the foreseeable future. Not supporting that with something as simple as "automatic escape special HTML characters" is extremely disappointing, and would actually prevent a lot of problems.
Not quite. They deprecated `<?` but not `<?=`, see here: https://wiki.php.net/rfc/deprecate_php_short_tags
Another PHP-RFC removed `<%`, `<%=`, and `<script language="php">` (I'll admit I didn't know about that one): https://wiki.php.net/rfc/remove_alternative_php_tags - but as with before, this specifically retained `<?=`.
The ASP tags were always a bit of a misfeature; I don't think I've ever seen it used even once. <script language="php"> is just weird because it's intended for client-side scripts :-/
It’s fairly easy to write clean and safe PHP. Any number of libraries and frameworks exist to do safe SQL queries and escape HTML. The problem is a lot of programmers don’t even know the vulnerability, not that it’s hard to fix.
I could bitch and moan about PHP or make a good living fixing bad code. Complaining won’t make that legacy code better or magically rewrite it.
Not saying this to diss PHPers; in fact, I like the PHP community for their get stuff done mentality, and I think they deserve better. If I were contracting for PHP, though, I'd make sure to negotiate strong liability disclaimers.
The ecosystem has a ton of exposed wires in builtins and libraries.
When the function's name is literally `mysql_real_escape_string` ... what does that tell you?
Seems like a strange function to have, although I could be foggy on my charsets.
What would you tell a small business that relies on clunky 10-year-old code to run their business? To rewrite it in a more modern language at huge expense and risk (given that a majority of rewrite projects fail)? Can you guarantee the new thing won't be just as obsolete and vulnerable and buggy in ten years?
These kinds of problems -- poorly-written and vulnerable code, amateur programmers, lack of professionalism, maintaining back-compatibility with an installed base -- are not specific to PHP. They afflict the entire software industry, and always have. Who could have seen into the future back in 2000 (when I first got exposed to PHP) that a new site would get probed by an army of bots within five minutes of going live? Or that it would be even harder today than back then to find and hire experienced programmers?
PHP has had many security fixes implemented since the early releases, but how can anyone force users of an open-source language to upgrade for their own good? Or pay someone to ferret out and fix vulnerabilities they have never got hit by?
Even brand new code has this problem. Look at all of the cryptocurrency code written in the last few years. We read about hacks and thefts and vulnerabilities every day, and that was written by supposedly smart people with access to modern languages and with knowledge of the contemporary security issues. And it still gets hacked. If we knew how to write perfect code that would still be perfect into the future I'm sure we would do that but until then we'll have to live with what we have. So far it has been sustainable, just less than optimal, if by optimal we mean what we can imagine rather than what we, as programmers, actually deliver.
Then there's the typical logical fallacy of taking a trivial problem of escaping SQL and conflating it with something more complicated, and comparing to eternal perfection.. yawn.
I think that one of the big mistakes made in the last 20 years is that every company needs its own custom software and that software is like an asset that you buy once and not a constant cost source.
The vast majority of businesses have no need for custom software and should be using 3rd party services. Then those 3rd parties have the income to dedicate to keeping the software secure.
Its honestly terrible how many local businesses have their own complex software built on some ancient version of a frame work which is sitting on an ancient server box in their office. Its a ticking time bomb no one wants to think about. Prolonging the explosion is not the solution.
About half the time the customer will find someone else who will happily bid on writing custom code despite my suggestion. That’s one reason the legacy code problem just gets bigger every year, and a lot of it shouldn’t have been written in the first place.
Do you know how old the software your bank uses is? Pretty much every government agency and utility you rely on? What price do you pay for that? A lot of that code has been rotting longer than any PHP web site.
There's no logical fallacy. I wrote multiple times that escaping SQL is essentially trivial in PHP, and has been not only easy but the recommended best practice. The problem is lots of inexperienced programmers don't know the problem to begin with. They would write vulnerable code in any language. I had to work on a Rails site a few years ago that was vulnerable to XSS and SQL injection, even though Rails by default protects against those things. Someone had gone around all of that because they didn't understand the problem in the first place. I don't know that any language can protect us from that.
The fact that you and many others in this industry think these arguments are in any way rational or defensible puts our industry to shame.
There’s a difference between an explanation and an excuse, and between counterexamples and “hand waving.” I’m sure it makes you feel superior to dismiss opinions and comments with vague references to logical fallacies or indefensible arguments, but just hauling out big words doesn’t make you right, or even make any sense.
I can’t fix everything wrong with software development. I’ve been doing it for 40 years and we just keep making the same mistakes. My small contribution is fixing broken code one customer at a time, at least leaving the campsite cleaner than I found it. I don’t lose a lot of sleep over our collective failure to write perfect software.
No serious org is going to use a product where you have to remember that the sql escape function doesn't work and you have to use the one that says real sql escape.
The MySQL escape functions are named the way they are because that's what they are called in the MySQL API, which PHP exposes pretty much verbatim. I don't see a lot of people using that interface in new PHP code (because Laravel and PDO), but it comes up on older code.
Again the problem is not obscure function names or that PHP makes it possible to shoot yourself in the foot. The problem is a whole lot of inexperienced programmers (and quite a few who should know better) not understanding the problem in the first place. If you don't know what SQL injection is or how it happens or how code can make it possible you aren't going to know how to protect against it. PHP does do it for you if you use PDO (more than 15 years old at this point), or any of the numerous other safe RDBMS libraries. This is like complaining that Honda makes shitty cars because some people put glass packs and spoilers on a Civic -- people use languages and tools wrong out of ignorance and inexperience.
I think it's clear that PHP has been taken seriously for some time, even if largely because of WordPress. It's not going to die off or get relegated to the language ghetto because it has some (obvious, well-known) flaws that serious programmers have known how to live with for literally decades. Regardless of what you think or see on Upwork, PHP contractors are not cheap. No one who can and will work on legacy code is cheap because most programmers won't even do that work if they can help it. Supporting legacy software, which includes improving and securing and upgrading it, is maybe the most lucrative and secure niche for programmers sitting there in plain sight.
https://wiki.php.net/rfc/deprecations_php_8_1
https://wiki.php.net/rfc/deprecations_php_7_4
https://wiki.php.net/rfc/deprecations_php_7_3
https://wiki.php.net/rfc/deprecations_php_7_2
https://wiki.php.net/rfc/remove_deprecated_functionality_in_...
https://wiki.php.net/rfc/deprecate_curly_braces_array_access
https://wiki.php.net/rfc/ternary_associativity
https://wiki.php.net/rfc/deprecate_null_to_scalar_internal_a...
https://wiki.php.net/rfc/deprecate-png-jpeg-2wbmp
https://wiki.php.net/rfc/mcrypt-viking-funeral
https://wiki.php.net/rfc/removal-of-deprecated-features
https://wiki.php.net/rfc/deprecate_mb_ereg_replace_eval_opti...
In the case of your example, what it tells me is that they had a "mysql_escape_string()" that they needed to remove but had to deprecate first to avoid breaking existing code, however bad it might be, and so replaced it with "mysql_real_escape_string()" -- which itself hasn't been in PHP for over 5 years, since that whole MySQL driver was deprecated. There's still a "mysqli_real_escape_string()", but that name is likely a quirk of history, as there's no matching "mysqli_escape_string()" for people who would like to use the supported driver but continue screwing up the charset.
(Edit: another comment reminded me of something that I knew once but had forgotten. The MySQL C API has the "escape_string" and "real_escape_string" functions in it which do precisely the same things the old PHP functions did. So this actually tells us even less about PHP the language, although it may tell us something more about MySQL.)
I was trying to go for the "PHP has tons and tons of terrible shoddy baggage" vibe.
https://preview.redd.it/v53przfht6n01.png?width=960&crop=sma...
Stroustrup quipped "There are only two kinds of languages: the ones people complain about and the ones nobody uses." PHP is the first kind. Like every language and tool before it that came with a low barrier to entry it led to a proliferation of bad code. My friends who work in ML/data science make the same complaints about Python -- it's easy to get something to work but the code quality -- ugh. And in a few years lots of that code will face the "upgrade and break it or keep it and cross our fingers" point that so much legacy PHP is at already.
When PHP came out in 1997 the other available products for putting web sites together, at least for smaller organizations, were:
- ASP (classic, not .Net)
- ColdFusion
- Perl
The first two were proprietary packages that required a license for the software and a license for the operating system (Windows). I got into PHP when a customer wanted to migrate away from Windows/ASP because of licensing fees -- they took the leap with open source, which was a big gamble at the time. The CTO had read "The Cathedral and the Bazaar" and swallowed the kool-aid. We still had to use SQL Server though, that company was committed to it across all of their applications, so I got to use PHP + ODBC for a while. Fun.
Perl had a fairly big base of CGI scripts but in most respects seemed worse than ASP, CF, PHP because Perl had a steep barrier to entry. PHP was an easy choice for shops looking to get off of ASP -- which Microsoft was making noises about discontinuing -- and ColdFusion, which several of my customers back then used, but complained about the cost (Adobe now owns CF).
So it was PHP. Then along came WordPress and the PHP world exploded. As you point out the language has had a hard time keeping up with the demands placed on it (Rasmus certainly didn't imagine Facebook-scale sites back then), and the evolving security threats (lots of web sites were purely internal back then, not exposed on the public internet, and the script kiddie hackers were still in nursery school in Kiev). Hosting providers sprung up to offer turn-key PHP/MySQL hosting, with the proviso that the site owner and developers did not control the PHP configuration.
Since 1997 a lot has changed and it's easy to point to problems in PHP and say "That could have been done a lot better." And that's true, but no one had that crystal ball back in the mid-90s. The push was to get something on the web. Planning for future maintainability has never been an aspect of software development we can boast about and the PHP code out there today is no different, there's just a lot of it.
For my part I push my customers to upgrade to the latest version and to do a security analysis and vulnerability test so we can find and fix the most egregious problems. Even this level of upgrading can get expensive and risky. I wish no one was still running PHP 5.4 in production in 2021 but wishing won't change that it's still fairly common, and companies using that code are only going to call someone like me after they've had a serious problem.
This is probably fair. :) I think PHP tried to combine Python's "batteries included" approach with Perl's "more than one way to do it" style, but did it in a pretty disorganized way that created lots of Catch-22 issues later -- when you get that popular, it makes backward-incompatible changes fraught with peril, even if you're addressing obviously craptacular past mistakes.
I think PHP has become pretty solid in version 7+ on, although my feelings about using it remain mixed. I've joked in the past that it's stopped being a cargo cult version of Perl and is now a cargo cult version of Java.
PHP is a light wrapper around C libraries.
> When the function's name is literally `mysql_real_escape_string` ... what does that tell you?
That it comes from the MySQL directly:
https://dev.mysql.com/doc/c-api/8.0/en/mysql-real-escape-str...
MySQL is the PHP of databases.
To me the language or online examples is no excuse for SQL injections for a long time now.
If Google and Amazon can’t find and hire enough developers imagine what that supply/demand and cost problem means for small companies. I have clients who have been trying to hire a f/t or p/t programmer for years. They can’t pay $100/hr for a simple web site. So they hire amateurs trying to get that experience needed to get a real job at a serious company.
Yes, they leave a trail of crappy code full of vulnerabilities and bugs. The only way to blame that on PHP is to criticize its low bar to entry, which is a good thing for beginners.
And the current bootcamp trend will only amplify that. Lambda has "instructors" that are students only 4 months ahead of the students they are teaching...
Now I went back to this guy's YouTube channel and saw that half a year later he finally did upload a bonus episode on how to mitigate SQL injections. One person in the comment section actually thanked him for the much needed video because their site was getting hacked. It is pretty hilarious to see this unfold but I do feel bad for the ~10k people who watched his videos.
If there was a penalty to the business, they would stop getting the bottom of the barrel programmer to work on their own. Yes it would make it a little harder to enter the market but any large business could still hire juniors and review their code properly.
In most other industries, you are responsible for your work. Usually you even need a formal certification first.
As soon as you turn your house in to a public venue (put your code in use for the public) you now have to worry about accessibility and safety. If that stair case collapses because of your dodgy building, you are liable. But you are free to fall off your own staircase in your own house.
So people are free to run whatever they want on their computer. But once you start taking user data, you now have legal responsibility. User data is hazardous waste that needs ultimate care.
That would go against the "Everyone can Code" trend and be perceived as gatekeeping.
For the past couple of years I have been working with laravel in a small company, and I really enjoyed it. The environment that it provides honestly is amazing. Documentation is super easy to read, laracast is amazing to bootstrap your knowledge in couple of weeks, and community is huge that you can find almost anything already built by them.
However its hard to find any big companies here that uses PHP, jobs popping up is mostly python, java and c#, thus sadly I have to leave php and learn java / python for the new big tech job (also for my own future). Its not that java / python community is bad, but I'll surely miss the laravel ecosystem.
There's one pretty big one....Faceledgar? Peoplebook? Something like that.
Though, recently PHP got quite a few features similar to hack, like type annotations.
"It looks like you're trying to create a web app front end! Do you need assistance with A) Implementing a dark pattern or B) Avoiding the use of dark patterns?"
Scary stuff.
There was a big "grassroots" push some years ago about pusing W3Schools docs out of the top Google results in favor of MDN; the same should be done with bad PHP code / examples. Because in practice, 90% of code is copy / pasted and adjusted.
There's just no big player behind PHP though, a party that wants to professionalize the language and more importantly its community. If there were, they would push for more authoritative tutorials and documentation. As it stands, the PHP docs are fine but are lacking information about SQL injection, and it's 10+ year old comments to that documentation that is often more valuable than the docs itself.
PHP is still one of the top languages out there but it has so much more potential.
[1] https://phppot.com/php/user-registration-in-php-with-login-f...
Don’t think this is just a PHP problem. All across the industry, people think of the OWASP Top 10 as some hyper-nerd shit that they don’t have to care about, and are indignant that you’d even mention it in design review.
So here's a partial list of issues you'd need to deal with:
- sanitizing input
- Escaping output
- SQL injection
- HTML injection
- XSS
- CSRF
- CORS
- Clickjacking
- DDoS and other resource exhaustion attacks
- Various timing attacks (eg password hashing)
- How to store passwords
- Depending on language, buffer overflows
That's... a lot. You can take this even further: you should assume you're going to get compromised at some point. What are you going to do to detect a breach? Or an active attempt to find a breach? What's your strategy for handling a breach?
Here's an analogy: we can tell you how to treat Poison Ivy without having to add a disclaimer that you're not qualified to be an attending dermatologist.
Should every tutorial be an entire 200-page course on all web security practices? Of course not.
But should every tutorial that inserts a user-provided value into a SQL statement ensure it's escaped? Of course. There's essentially literally never a situation where you shouldn't do that. It's not just to be "production-ready" -- it's so basic as just to make sure the query will still even parse if the user includes a quote character in their input.
So why on earth are you defending this mistake?
That might not be true for other security issues but I think tutorial writers should be fine saying "here is a bit of magic that fixes a problem called csrf. We won't cover that in this course but leave this in here"
Oh, that unicorn that everybody takes about, yet nobody does anything with it
So, how do you sanitize input?
you save in database escaped strings?
allow only "english" letters?
>- HTML injection
>- XSS
those two belong to
>- Escaping output
don't they?
>- Various timing attacks (eg password hashing)
>- How to store passwords
just use state of art auth/login handling libs?
>- DDoS and other resource exhaustion attacks
I don't think I'd add it there, isn't it handled by firewall / infrastructure than app directly?
Although most DDoS attacks happen on the layers 3, 4, and 6 of the OSI model, your application still has to be hardened against resource exhaustion and other DDoS attacks.
For example, if you have a REST endpoint that starts a complex query which might return a large result given some specific query parameters (e.g. your limit parameter is not bound, so I can set limit=1000000), running 10000 requests against it from different hosts (malicious or not) may bring down your database server.
The tutorials don't even need to talk about security: just tech secure by default APIs. If the programmer later needs more flexibility (which should be understood as an advanced topic), they ought to learn that you must sanitize user input in raw queries.
Those stupidly bad PHP tutorials that show you how to concatenate a URL parameter to an SQL string were easy to understand, and taught me about everything from writing PHP/SQL, setting up a MySQL server, networking/opening ports, designing database tables, designing an application, and much more. The motivation I got from learning so much in so little time led me to keep learning new things, including learning and understanding why all that code I wrote when I was younger was so bad.
If those shitty tutorials get copy and pasted into production codebases, that's the company's fault for hiring a lazy/bad developer, and for not catching the vulnerability.
At a certain point it turns from tragedy to farce.
Don't get me wrong, PHP taught me a ton about programming and was a very important language, but yeah...
I don’t think fixing Google’s index is enough and probably not you something we can rely on.(there are other search engines)
One problem could be that official PHP documentation only includes examples for using a specific function, not an entire use case from start to end. That would mean that examples would also include lots of HTML, CSS, SQL and JavaScript. But then of course it will no longer be a PHP documentation.
Writing correct up to date examples is very time consuming. Sites like w3schools tries to do this, w3schools was bad in the past but has become better, but it is also a commercial site so nothing you don’t want to contribute to with your own examples. At the same time it is understandable that w3schools wants something in return.
Another idea could be to contact site owners of these tutorials, but then they probably want the correct fix. This can also be time consuming.
Maybe an index of approved tutorials voted by the community and then make sure this index gets high on Google ranking.
By updating all of the old, insecure tutorials to redirect towards secure answers instead.
Details here: https://paragonie.com/blog/2018/01/our-ambitious-plan-make-i...
I googled for `php mysql email register`. This returns tutorials, how-tos, code snippets. Most results include flawed DB statements.
Nothing to do with Google itself, Google being vulnerable to SQL injection, or completely arbitrary websites being vulnerable.I wonder if the more obvious 'PHP MySQL Tutorial' would also return this. I don't think that this changes the general point of the article, there is a _ton_ of bad information out there. I did the same with "Node.js JWT" and the results were even worse.
https://www.php.net/manual/en/function.mysql-real-escape-str...
I've never seen a post on this site about PHP that was associated with a positive idea.
So here's some advice I wish someone had given me back then:
Please try to at least read and understand OWASP top ten security risks¹ before writing applications that anyone actually uses. Also please be aware that you can write insecure code in any general purpose language. Most of the bad PHP code is around because it was a popular language with hobbyists, similiar to Javascript and Python today. Languages might be better (or worse) in certain aspects but they still can't protect you from bugs in your programs logic. Only diligent planning, understanding of best practises and proper communication can help prevent those.
Same person always bragged how important is security and how he/she is good at it. The management ate it. It's only when real money are lost and the C-Suit want heads to roll then maybe Mid-Low management will start take my words seriously...for a few months.
There's just no easy way to verify the security of an app. Being security aware and try to make the code secure will cost extra time and make you a diva.
Right now I simply refuse allow those madness infect my code and create clear paper trails, so I can keep my code/job rather sane in the asylum.
$query = "SELECT * FROM wp_misure WHERE Id = '".mysqli_real_escape_string($link, $_GET['id'])."'";
This is not vulnerable to SQLi unless I misremember how real_escape_string works.The 'real' supposedly alludes to the fact that `mysql_real_escape_string()` accounts for character encoding (if specified correctly) unlike its sibling `mysql_escape_string()`.
So, yeah, I'm afraid 'less funny'. :-/
https://docs.python.org/3.8/library/sqlite3.html#sqlite3.Cursor
# Never do this -- insecure!
symbol = 'RHAT'
cur.execute("SELECT \* FROM stocks WHERE symbol = '%s'" % symbol)
# Do this instead
t = ('RHAT',)
cur.execute('SELECT \* FROM stocks WHERE symbol=?', t)
print(cur.fetchone())
# Larger example that inserts many records at a time
purchases = [('2006-03-28', 'BUY', 'IBM', 1000, 45.00),
('2006-04-05', 'BUY', 'MSFT', 1000, 72.00),
('2006-04-06', 'SELL', 'IBM', 500, 53.00),
]
cur.executemany('INSERT INTO stocks VALUES (?,?,?,?,?)', purchases)More advanced, 90s Perl style: setup something like a taint bit on outside variables which has to be cleared using an escape function to avoid an error.
OOP variant: A class system could be used to make something like execute() only accept a SqlQuery instance and that class throws a fatal error if you concatenate a regular string. That still allows someone to run arbitrary strings through whatever marks strings as safe but that requires doing additional work rather than forgetting and is easier to audit.
Nicer, possibly less safe variation: implement something like Python’s __add__ / __radd__ so query + string has the string escaped automatically.
More advanced: make the query method only accept constants defined at compile time with some escape hatch function which is clearly marked as unsafe: totally_insecure_query(). You need some way to combine predefined fragments for conditionals but that should be possible in most modern languages.
Rust example: https://polyfloyd.net/post/compile-time-prevention-of-sql-in...
It's still not safe
SQL injections are incredibly easy to test for, and exploit scripts like SQLmap make it trivial to dump an entire database server’s contents with a single point of entry (and, if you’re unlucky, tamper with or even delete your databases). There’s practically no excuse for not covering it in a tutorial, or at least giving some forewarning about it.
I really REALLY can't stand it.
$s = $dbc->prepare("SELECT * FROM table WHERE field = :foo"); $s->bindValue(':foo', $_GET['foo']); $r = $s->execute();
But all of that of course doesn't help if people don't use it.
Of course the end result is probably they they have less PHP expertise than you might hope. But these are really sad failures.
https://en.wikipedia.org/wiki/.local#Microsoft_recommendatio...
However retail stores were almost entirely composed of Linux machines except for the manager's desktop. The corporate software used in these Linux machines would always pull samba which in turn pulled avahi. As soon as the software was installed post imaging because of licensing requirements connectivity with central servers was interrupted and the person installing it (which was always a different person because the stores were spread through the country) will often scratch their head, specially those who don't bother to read notes.
const express = require('express');
const app = express();
const mysql = require('mysql');
app.get('/', (req, res) => {
const connection = mysql.createConnection({
host: 'localhost',
user: 'me',
password: 'secret',
database: 'my_db'
});
connection.connect();
connection.query(
`SELECT a FROM b WHERE x = ${req.query.y}`,
(err, results) => {
res.send(results[0]?.a);
connection.end();
});
});
app.listen(1234);
Now this will be a google result somewhere for how to do a query that contains an SQL injection vulnerability.I fail to see the point of this article, as pretty much anyone who enters into web programming understands that there is something called an SQL injection vulnerability that they need to be aware of.
My experience in the past couple of years as well, and not just for PHP. I wonder if anyone has looked into tutorial results with and without privacy controls to see if the quality is meaningfully different.
Let the poor newbies learn to code by seeing the simple beauty before drowning them in security nightmare scenarios.
Yes. I’ve seen this from highly-paid staff and contractors at multiple places in .com, .edu, and .gov. This includes commercial licensed software, big name consulting companies, and ostensible security experts. I’ve also seen them “fix” the problem by looking for the PoC test string and only rejecting that value.
Unsafe defaults make it much easier to get something to “work” without noticing problems because the happy path works and is what most people focus on testing.
Abso-freakin-lutely. It may not be direct copy pasting of code, but often it'll start as that then be tweaked as appropriate for the project at hand.
Even programmers not doing this are frequently going back and looking at their own code doing similar things or other similar code in codebases they have access to (eg internal libraries). Better programmers will do similar things but also recognize the flaws in what they're using.
After all, you could implement the exact same thing in userspace.
But yes, anytime you have one program writing instructions for the other, you wind up with a risk for bad composition of those instructions.
Fortunately, frameworks and libraries (for SQL and HTML) are increasingly successful at adoption and removing the risk of the programmer using low-level unsafe primitives.
What a surprise!
Those are great tools and you can always use raw sql in exceptional cases
ORMs are a heavyweight, something that is fundamental in your design. Parameterized queries are just regular SQL queries, but safer.
If it's raw PHP I wouldn't want to compete with a lot of great SO results out there, but you also have to take into account circumstantial matters, like whether the given approach is appropriate to the needed output or input you are dealing with.
For this reason I'd recommend arranging for some kind of code review even if you ask online strangers for input.
These eliminate SQL injection. But you have to use them and not just concatenate user input to SQL queries.
There are pdo drivers for most popular databases
https://www.php.net/manual/en/book.pdo.php
Honestly it’s my favorite way of accessing databases (compared with Java Perl and python)
$stmt = $pdo->prepare('INSERT INTO user (email) VALUES(?)');
$stmt->execute([$email]);
For a full example you can look here, includes injection exampleWith so much obvious misinformation on stack exchange, why is Google so blase about directing searchers to the site?
In order to show you the most relevant results, we have omitted some entries that contain shitty code and bad security practices. If you like [repeat the search with the omitted results included].
I can't imagine this being controversial. No one would complain at all about being affected.
In this case, the help is fundamentally wrong. Other than "what is an example of a dumb programming mistake?", there aren't really questions to which a valid answer involves concatenating arbitrary strings and executing the result as an SQL command.
If your question is, "how do I execute an SQL command?", there are many better examples to use. If the question is, "how do I store user-supplied data in the database?", or "how do I query using user-supplied values", then the answer should not give you what amounts to an accidentally working hack.
SQL is a language of its own. It has a syntax and a grammar. When generating SQL from PHP (or any other language), you're switching languages - there must be a translation step involved. Any answer that doesn't bring this up explicitly is just wrong.
If you're already that good, how does seeing a CSRF token in an answer actually impact you? Does it prevent you from copy/pasting someone's "example" code?