Our Ambitious Plan to Make Insecure PHP Software a Thing of the Past
paragonie.com
paragonie.com
Because the problem is there are many "old" accepted answers, with high upvotes, that will always come up as number 1 or 2 in google searches.
Given PHP has changed so much, many of those answers are outdated, use incorrect and insecure methods, and some are now just wrong. This is not just security - but a whole host of answers.
The "meta" StackOverflow rules will tell you to downvote the old answer and post a new one - but that is not practical - and will take years to take effect. Plus, many people simply read the first large upvoted answer, copy + paste the code, and move on.
edit: I guess it would be nice to be able to "flag" an accepted answer (not a question) as outdated, get 5x people with gold badges for that tag to accept it - and then the answer is highlighed as wrong/out of date (or even deleted). Something like that.
Possibly. I wouldn't even know where to begin.
> Because the problem is there are many "old" accepted answers, with high upvotes, that will always come up as number 1 or 2 in google searches.
Yeah, that's my concern. I can definitely edit anything tagged [php], due to having a gold [php] badge, and I think I can edit anything because I have a reputation higher than 10,000.
The hardest problem for me, here, is identifying these old accepted answers with high upvotes.
My general approach is something like this:
https://stackoverflow.com/questions/tagged/php+encryption?so...
https://www.google.com/search?q=site%3Astackoverflow.com+php...
If 5 gold people accept it - then the answer is formally highlighted as out of date, or even deleted.
You could raise this on Meta Stackoverflow as one possible way to start: https://meta.stackoverflow.com/
edit: There probably should be another flag option - called "security" - where even if an answer "works" and is "in date" - people can flag it as insecure due to a better option. Think of all the stupid SQL injection answers. You can downvote it to hell - but sometimes they should just be flagged/deleted.
Signed, someone who's done a lot of legacy code maintenance (have you tried to find VB6 or .NET 1 doco these days?)
Ask the folks on meta.stackoverflow.com. Be prepared for some resistance -- the concept of calling out bad answers in any way more nuanced than downvotes or comments is not popular -- but your involvement with the greater PHP community may give you some extra leverage.
It would be a lot of work, but I think it's easier than trying to get authors of defunked blogs to take down 10 year old answers.
As a side-effect, this increases awareness among developers that you can't blindly accept what's on SO. If developers begin to lose trust in SO, then SO is going to be incentivized to do something about, or go the way of expertsexchange.
[0]: https://plugins.jetbrains.com/plugin/7622-php-inspections-ea...
I was thinking that they could do analysis on code snippets that are copy-pasted into the editor. It should be straight-forward to compare the contents to a finger-print database and issue a warning when they find a match to online code examples that are marked as vulnerable.
For greenfield projects it can be a godsend, if you have the experience to know which warnings you should disable and the discipline to keep the entire code base warning-free. I've done this with StyleCop / FxCop in C#.
Here's a list of PHP static analysis tools: https://github.com/exakat/php-static-analysis-tools
$sql = "SELECT * FROM table WHERE id = " . $_GET["id"];
It's all about education. This does apply to any language.Your goal is laudable, just not sure it's practical. Did you consider focusing on publishing and promoting net new content instead? Get traction that way, and that content will move up the Google serps, effectively moving the old/bad content down.
We've been doing that for years. We've hit diminishing returns because:
1. There is a lot of incumbent material in the same genre, most of which is 10+ years old, but people still link to it in droves.
2. We don't support the at-best-sketchy SEO industry that's sometimes arm-in-arm with adware.
If you read the 2018 guide this post mentions a few times, you'll notice that it, in turn, links to relevant blog posts (and open source libraries) spanning back to early 2015.
Asking a 3rd party site to change a link seems easier than asking a different 3rd party site to rewrite content.
I'll update the article to try to make it clear that "link to clearly superior content" is a viable alternative to rewriting said content, as long as the same goal is achieved.
Since we all saw and remember how Perl regained it's top spot as most popular programming language, I'm sure this will work out wonderfully. :/
See https://w3techs.com/technologies/overview/programming_langua...
Anyone who wants a more secure Internet must necessarily be interested in improving the security of PHP.
I didn't imply that 83% of developers use PHP. I'm sorry if anyone read it that way. I'm zeroed-in on the "what powers the Internet" statistic.
We could ignore that crowd, but guiding them down the right path is better for everyone.
Edit: I'm also not convinced that node.js, which is gaining ground with the same crowd, doesn't have similar issues. Footguns aren't unique to PHP.
PHP may not be the best of all possible languages, but it's by far the most widely available.
What they provide now is better and more scalable than old school CGI. Most of the shared hosts are using LightSpeed[1] as it squeezes as much as possible out of PHP in a shared environment. That vendor, and their low end shared host customers, aren't dumb. They will respond to market changes and make node.js a 1st class support item when it is clear that's where the money is.
Because people get into programming via PHP via writing extensions for popular PHP software (WordPress) because that's what they can get paid to do as an entry level dev. It would be prudent to have them get into it in a way that doesn't cause exploits.
Sure everyone and their dog may one day get into programming via Javascript via Ghost or something else along that line, but that's just not how it is right now. How it is right now is people writing HTML forms that post into raw SQL queries - you can make rookie mistakes like that in any language, no matter which one happens to be the top dog of the moment.
I also have to note that on a skim a lot of the comments you linked to can be distilled to "No it isn't"
Telling potential users to spin up a VPS or type some command line instructions to install code is too complicated for many users, even though it may seem trivially easy to a developer.
The whole "start up a little webserver in the same language" trend makes everything much* easier to develop.
Where PHP still has an edge is deployment for non-development. If you just want to drop in some software and use it on the web (e.g. a bulletin board), PHP is still easier in many cases for novice users. But that's not development, it's just deployment.
I would even hazard that correct deployment of that software in a secure way is made harder by PHP's ease of deployment, as you have to rely on permissions in lieu of separate locations that have no remote read access, as many frameworks implement.
php has builtin webserver since 5.4. that's like 5-6 years ago
I actually agree, but that's not the approach that's pushed. In python the "tiny http server" is explicitly advertised as insecure and unsuited to production use. In Java, embedding Jetty involves dozens of arcane lines and manually translating suggested XML files into code - not something a beginner can do. What other language than PHP can I dump a single file on a shared host and have it be running?
(Ironically Java is actually a legitimate answer here, if the shared host ran an application server like Tomcat and accepted .war uploads. But I don't think I've ever seen a shared host that offered that?)
Sure, but we're talking about developing, and that's a pretty easy way to get started.
In Python, don't you have Gunicorn, Tornado and Twisted?
In Perl there's Mojolicious and Dancer.
Ruby has Rails, Sinatra and probably a least a few more.
Java... Well, IMO Java has a habit if either not delivering simple smaller projects, or communicating they exist very poorly (but I'm not really in the loop so my opinion may be very uninformed). Tomcat was too big and complex to fit this need a decade ago, so I doubt it does it well now (but maybe I'm wrong?).
> What other language than PHP can I dump a single file on a shared host and have it be running?
My point is that needing a shared host to get started is actually a step you often don't have to wait for now. If you're a developer, it's easier to just start up your dev locally and work out hosting in a bit.
If you're developing something beyond the simplest things, the host allowing drop in scripts is not actually a problem I think. For anything that's super quick and dirty, you still have CGI.
That's the point I was making. The drop in script support isn't really all that beneficial to PHP developers, but it is very beneficial to regular user that just was to deploy a PHP webapp of some sort, such as a bulletin board or blog software.
> My point is that needing a shared host to get started is actually a step you often don't have to wait for now. If you're a developer, it's easier to just start up your dev locally and work out hosting in a bit.
I have to disagree. It's silly to try to develop something you can't actually run. Getting your software in front of actual users is the critical path; everything else is secondary. (And exposing your dev laptop as a web host on the internet is pretty complex in practice for most people, quite aside from whether it's a good idea)
> For anything that's super quick and dirty, you still have CGI.
Do any of the frameworks you listed (Gunicorn or Mojolicious or Rails or...) support running as CGI? Is it documented in their tutorials?
It's trivial to run. Get a minimal AWS instance, or a small digitalocean instance, or whatever. Hosting is not a problem these days. Godaddy is offering managed (they patch and provide support) VPS instances for $18/mo right now. Surely not as cheap as some dedicated host, but also more secure and if you're actually spending your time developing something, not a lot to pay.
Nobody is saying expose your laptop to the internet. But getting started isn't about getting someone to look at your stuff, it's about actually getting started and getting some code written.
> Do any of the frameworks you listed (Gunicorn or Mojolicious or Rails or...) support running as CGI? Is it documented in their tutorials?
When you control the webserver running a subprogram as CGI (which is what I was referring to) is trivial, and can be handled in a few lines of code.
If you're talking about whether the framework has instructions on how to run as a CGI, I'm going to go out on a limb and say yes, they all do because that's step one in telling people how to run your stuff when making a framework, where it makes sense. In some cases it's just a WSGI/PSGI etc server and you can interchange them. It may not make sense to run twisted as a CGI, but if you write WSGI you can just use django, which does support deployment as a CGI. Mojolicious and Dancer support it. I'm pretty sure Rails and Sinatra do in some way to.
These trivial things matter when you're getting off the ground. Dropping money on that idea you were playing with in your evenings is a big psychological step. A couple of hours faffing with server admin can be even more offputting.
> Nobody is saying expose your laptop to the internet. But getting started isn't about getting someone to look at your stuff, it's about actually getting started and getting some code written.
Disagree. The goal isn't to write some code, the goal is to get a viable business, and these days business concerns - the famous product-market fit - are a much bigger risk factor than technical ones. A mostly-static page with a simple text form that can start getting you actual customers puts you much closer to that than any amount of code running on your dev laptop. (It's different when technical innovation is at the core of the business - when the actual code is the biggest risk factor - but in that case you're probably not doing web stuff and probably not using any of these languages).
> If you're talking about whether the framework has instructions on how to run as a CGI, I'm going to go out on a limb and say yes, they all do because that's step one in telling people how to run your stuff when making a framework, where it makes sense. In some cases it's just a WSGI/PSGI etc server and you can interchange them. It may not make sense to run twisted as a CGI, but if you write WSGI you can just use django, which does support deployment as a CGI.
It's never "just" though; these differences are important. Every extra step beyond "upload this file to the host" probably cuts the number of projects that get off the ground in half. And a lot of these frameworks will tell you how to "run" them in a one-off way but completely gloss over how to set them up so that they'll still be running after you restart the server you're hosting on.
I just had a quick look through the django tutorials to check I wasn't talking nonsense and it's even worse than I thought. The "installing" page gestures vaguely in the direction of virtualenv (which is how people actually use django in practice) but it's not integrated in the tutorial at all. The 7-page "beginner tutorial" only ever uses the officially-not-secure-enough-for-production local development server. I was excited by the link to an "advanced tutorial about creating reusable apps", but turns out that's just telling you how to package up your webapp so that other people can run it locally with the development server. Nothing about WSGI, not one word about how to actually put your "webapps" on the web. I don't mean this as an attack on django specifically - I like django, and it's documentation and tutorials are better than a lot of options - but no wonder people keep using PHP.
Why not? There's a large and active community, both the core dev team actively improving it, and millions of programmers building applications.
Just because you don't like something doesn't mean the rest of the world agrees with you.
The same thing happens about four times a year when COBOL is mentioned and someone realizes to their horror that the plastic card in their wallet works thanks to a language whose last major revision was in 1974.
Perl still powers a lot of stuff. It fell behind PHP because PHP outpaced it for growth in web development. Nothing has outpaced PHP's growth yet, no matter how badly trend-addicted programmers want it to.
You're also falling victim to this same fallacy. Something did eclipse PHP.
JavaScript.
Edit: Thank God!
There's also Node.js which is catching on really fast because it fits that role of "JSON over REST/GraphQL provider" really well.
Oh, I'm well aware. I'm a full time Perl developer, have been for a long time, and love the language. It's just interesting to see history repeat itself.
Not likely when professionally written code is full of errors, many security-related (e.g. attempting to load and execute .gifs). I recently presented a compilation[1] of the errors produced by one widely-used commercial ad function. If this is how a professionals write commercial code, I don't want to imagine what amateurs have been doing.
[1] https://www.reddit.com/r/web_programming/comments/7o8dzf/cop...
There are some great, new cryptographic functions that have been implemented in PHP >= 5.5
Password_hash() and password_verify() are so simple, it's hard to mess up password hashing now. When I upgraded my projects to PHPa7, I replaced dozens of lines of code with those 2 functions alone.
But I have seen plenty of implementations of them that still fall back to old more convoluted and error prone methods when you are using some old version of PHP.
The universe of developers with PHP projects to maintain is filled with people who do not share the same goals and constraints that you might enjoy.
There is an enormous amount of lousy PHP code, and more being made by clueless developers. But please do not dismiss the need to support old PHPs as being driven primarily by those reasons.
1. The PHP project itself has EOLed 5.3.3, however distros continue to support it with backported security and bug patches of their own.
2. PHP 5.3.3 (with backported security and bug patches) remains the default in CentOS 6.9, which is supported until 2020. More recent versions are not available via their repositories. Hosts would have to upgrade PHP outside of the CentOS packages and assume the maintenance burden from then on.
3. About 50% of sites running PHP are at versions less than 5.5:
https://w3techs.com/technologies/details/pl-php/5/all
https://w3techs.com/technologies/details/pl-php/all/all
4. Updating PHP is not like simply updating my Web browser. Real-world production hosts like mine are filled with various work by various developers over years. Bumping PHP further than a maintenance release would almost certainly mean unnecessarily breaking things that are hard to find, probably tricky to fix and written by people I’ve never met who are long gone.
Look, one-line register_globals polyfill.
"PHP 5.3.3 (with backported security and bug patches) remains the default in CentOS 6.9, which is supported until 2020. More recent versions are not available via their repositories. Hosts would have to upgrade PHP outside of the CentOS packages and assume the maintenance burden from then on."
https://news.ycombinator.com/item?id=16161455
The point isn't that you can't or shouldn't do it, but that it is much more trouble than you might think for many people. There are implications that apply to others that you might not see or care about for your particular situation.
The Node team has done a great job here, they have a number of ways of doing managed source installs that avoid a lot of the ugly hassles you can usually hit. Ruby has rvm which also handles this quite well. This helps work around any friction you might get at the distribution level.
If PHP is being held back by distribution maintainers then that's a problem that the PHP community should fix. 5.3 came out in 2009, it's ancient.
But they'll finally listen to engineering... any year now...
It sounds like you are talking about providing hosting for older versions of PHP code. Which I of course understand is a necessary thing. You can't force people to upgrade their codebase. They'll just find another host.
Sometimes it's for lack of knowledge (PEAR? Composer? What's that?) but all too frequently it's outright hostility to the very idea, like if it isn't PHP core it's not even worth considering.
`password_hash` and `password_verify` have been around for ages now and if your PHP is old enough that it doesn't support it, that PHP version is no longer actively supported and is probably riddled with unpatched security holes, so good luck with that!
1) Sign (HMAC) all the session ids that your server issues. This allows requests with bogus session ids to be rejected at the network borders without doing any I/O or hitting the database.
2) Use web crypto (now supported by all major browsers) to have clients generate a private key with which to sign all requests. Using session keys as bearer tokens opens users up to attacks.
3) Do NOT send passwords to the server! Use passwords to decrypt the private key, and do not expose the decrypted key to external Javascript. And make sure the key can't be exported.
4) Clients authenticate new devices using two-factor authentication. If the person is using a previously authorized device and knows their password this may be considered two factors already. Unless the password was saved, in which case they better have a password on their device. Ultimately you gotta trust the OS.
5) Authentication and authorization for data may be done automatically by a side-channel (QR code via camera, or bluetooth) with the proof submitted to the server by either device. Revocation ultimately needs a blockchain.
6) If you lost all your authorized devices, the backup should be: M of N public keys, plus a passphrase you know. This is only for rare cases and the passphrase can be weak.
No more passwords except for the above!!
First of all, you have to agree that a security requirement in addition to a cookie doesn't make things less secure.
Secondly, with Web Crypto the Web has a way to mark keys "non exportable". If the website is sending you the wrong resources then of course anything can be sent, and web-based code isn't the ultimate way to protect the user. The same is true of other approaches. However if the initial code download wasn't tampered with, then you are far more protected. Because the secret private key won't be exported from the browser website. And it won't be accessible to anyone outside the JS environment that asks for your password or finger to derive a key to decrypt the master key from the local database. And in that JS environment, you can make sure (via closures) that no one gets access to it in "userland".
OH AND YOU SHOULD ALSO BE USING A PRIVATE KEY PER USER TO ENCRYPT DATA AT REST ON YOUR DATABASE, AND STORE THIS KEY IN THE DB MULTIPLE TIMES - EACH ONE ENCRYPTED BY THE USER'S DEVICE KEY. You don't store these device keys. Successfully authentication requests from the device send this key. So once again you need to obtain this key in order to unlock user's info needed for the request. And users can send permissions to unlock their information to each other in sidechannels. You can take this security VERY far...
So it's strictly more secure than the server side database for passwords, even hashed and salted with key strengthening. BUT, don't advertise it because then it introduces security attacks where people over-rely on this to te detriment of the vectors mentioned in the article.
PS: Oh. This was written in 2011, before the Web Crypto standard I am referring to was published and adopted by all web browsers. I do NOT recommend doing the crypto methods in JS! And yes it has a secure RNG now.
https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_...
Also Object.freeze() is a thing now.
There is prior work in this genre. Something like SPAKE2-EE might be worth looking into here. https://github.com/jedisct1/spake2-ee
> It doesn't mean you should be using the session cookie alone as a bearer token to access a session.
Well, maybe.
A random ID that just tells PHP where to look for the session data, with all the data persisted server-side, is secure as long as it's transferred over HTTPS. Most frameworks/libraries abstract the implementation details away, but generally:
<?php
use ParagonIE\ConstantTime\Base32;
$random = Base32::encode(random_bytes(32));
This value will be unpredictable and doesn't require an HMAC to ensure this property. The only time the HMAC adds value is if you're using the user's computer as a data mule for the entirety of session state rather than "look up this identifier in a database".In those use-cases, you enter the usual JWT abuse territory, as outlined here: http://cryto.net/~joepie91/blog/2016/06/19/stop-using-jwt-fo...
In this genre, we're working on PAST (although this is probably going to be renamed before it's finalized) to solve the cryptography flaws baked into the JWT standards (collectively, JOSE): https://github.com/paragonie/past
That doesn't solve the "replay attack" issue (which may be what you were referring to with bearer tokens).
> OH AND YOU SHOULD ALSO BE USING A PRIVATE KEY PER USER TO ENCRYPT DATA AT REST ON YOUR DATABASE, AND STORE THIS KEY IN THE DB MULTIPLE TIMES - EACH ONE ENCRYPTED BY THE USER'S DEVICE KEY.
I'm not entirely sure what you're getting at here. If I needed to share a key across devices, I'd either use Diffie-Hellman or Shamir Secret Sharing to accomplish the task (depending on use-case and threat model).
Perhaps there's a lot of implementation detail that's not being discussed here that I'm missing and what you're saying is a conservative local maximum, but it stuck out a tad bit.
Today we wrote up an article about this, actually, referencing your guide:
It goes into more detail about all this.
Neat. I'll have to give that a read in the morning.
Although, it looks like one of your links in the opening paragraph under the "Web Security in 2018" header is broken, and presumably that was the one meant to link to our guide.
Information on older version should not be pruned as there are legitimate reasons to keep them. Not everyone is using PHP 7; what do you do when you inherit an older code base; what do you do when you just need to modify a few things on an older code base; what if you are trying to learn security based programming; what if you are trying to learn how to break into systems (to then learn how to protect them); what if PHP7 is not available or feasible for your project; etc.
What can we do about that, short of “use framework X or Y” as they are the only ones peer reviewed?
For example...there's nothing about current day PHP that makes it more susceptible to SQL injection than any other dynamically typed language with easy string interpolation. And the official PHP docs do guide you down the right path for SQL.
What the talk really exposed was a few similar bugs found in various projects (which is good!), and exposed a fundamental misunderstanding of a language by the researcher due to unfamiliarity. This was all covered in depth here at the time.[1]
* https://wiki.php.net/rfc/libsodium (PHP 7.2)
* https://wiki.php.net/rfc/mcrypt-viking-funeral (PHP 7.1)
* https://wiki.php.net/rfc/random-function-exceptions (PHP 7.0, largely the result of a mailing list discussion critiquing the original implementation of the new CSPRNG functions)
There is plenty more we want to work on in the coming months.
I recall the python docs have a big red warning box that you can enable shell-style-single-string mode instead of a list, but it's highly dicouraged due to security problems. php has about 5 ways to execute programs, but all of them enforce this insecure interface.
And if you think the history of PHP isn't applicable, then go and find the Golang library authors who are advocating filtering as a defense against SQL injection!
If you're a professional PHP developer or a company that builds on PHP, it would be very embarrassing to find yourself prominently featured on such a list. Which would create an incentive for those people to clean up their work so they can get off it.
As things stand currently, publishing outdated and dangerous information costs the publisher nothing, so they see no reason to stop doing it. Create a cost by attaching reputational damage to the act, and you create a reason for them to stop.
I'm hesitant to do this myself, because it might open us to legal action, and I don't have the emotional bandwidth or cash reserves to fight a lawsuit right now.
Whether that's a feature or a bug of PHP is an exercise I leave for the reader.
This isn't to say that there aren't good YouTube videos, but for each one of these there's easily a hundred where people with no clue are explaining PHP as if they know everything.