In short: PHP has a tendency to be vulnerable-as-a-default, the barrier to entry is so low that every noob who barely just learned HTML can already begin writing dangerous code, even the largest web apps in PHP have gaping security holes, and I consider PHP itself to be just an elaborate content management system more than a real programming language.
To break down each of those points:
The last time I made a solid effort to learn to code in PHP, I came to realize that the default php.ini on my system had some rather stupid options turned on by default. For instance, the
include() method would be allowed to include PHP code from a remote URL beginning with "http://". It's things like this that make PHP insecure as a default. I now have learned to carefully prune through my php.ini before installing any PHP web apps on a new server just to make sure no stupid defaults are enabled that will leave my server vulnerable.
The barrier to entry is so low in PHP that people who have no business writing program code are given the tools to do so. A good friend of mine does freelance web security consulting and says that a very good majority of PHP-powered sites he's come across have been vulnerable to SQL injection, and attributes this to the fact that many PHP tutorial sites don't mention SQL injection when they get to the chapter about databases. They'll recommend that you just interpolate variables directly into your SQL queries.
Case in point: the very first result for Googling "php mysql tutorial" that isn't from php.net is this link: PHP/MySQL Tutorial - Part 1. When this tutorial gets to the insertion part, it recommends you just formulate a query like this:
SELECT * FROM contacts WHERE id='$id'
SELECT * FROM tablename WHERE fieldname LIKE '%$string%'
Coding practices like this will leave you a lot of pain to come in the future. I'm not a PHP tutorial site so I won't even bother to explain how to avoid SQL injection in PHP. I won't use any of your code on my server so your own stupidity will be your own downfall, and it won't be my problem.
As an example of a large PHP web app having gaping wide security holes, just read about how my server got hacked through phpMyAdmin. In short, there was a PHP script in the "setup" folder that ended with a .inc.php file extension (indicating it was meant to be included and not requested directly over HTTP), and it would execute system commands using data provided by the query string. I've ranted about how badly I hate PHP even more because of this on that blog post. And that in Perl, this sort of thing wouldn't even happen, because an included script would have to go out of its way to read the query string; it wouldn't just use the query string "by accident" like PHP scripts are apt to do.
Besides SQL injection being one of THE most popular attack vectors for anything written in PHP, but if I ever hear about a PHP exploit besides that it almost invariable is this: somebody fooled a PHP script into including a PHP source from a remote domain. Example:
Your site has URLs that look like this,
And your "index.php" there will take "p=home" and include "home.php" to show you the home page. Okay, what about this then?
And your index.php includes pwned.php from that malicious looking URL and now a hacker can run literally any code they like on your server. I've witnessed sites being pwned by this more times than I can care to count, oftentimes because the php.ini was misconfigured as a default.
Moving on to the last point, I don't consider PHP to be a real programming language. It is more like a web framework, like Drupal or MovableType or Catalyst, that is packed full of tools specifically geared towards the web. PHP has thousands of built in functions for everything a web app could imagine needing to do, from MySQL to CGI. The web page "PHP in contast to Perl" sums up all of the problems with PHP's vast array of global functions. They're inconsistently named and many of them do extremely similar things.
Contrast that to Perl, where the core language only provides the functions you would expect from a real programming language, and to do anything "cool" you'll need to include modules which provide you with more functionality. PHP fans often say it's a good thing that PHP has MySQL support built right in, but then I point them to the functions
mysql_real_escape_string. What is with that? Was the first function not good enough, that somebody had to write a second one that escapes strings better? And they had to create a second function so they don't break existing code that relies on the behavior of the first?
In Perl, if I was using the DBI module for SQL, and I had a problem with the way that DBI escapes my strings, guess what I could do: I could write my own module that either inherits (and overrides) from DBI, or write a new module from scratch with an interface very similar to DBI, and use it in my code. My code could still be written the exact same way:
my $dbh = Kirsle::DBI->connect("..."); my $sth = $dbh->prepare("INSERT INTO users SET name=? AND password=?"); $sth->execute($username,$password);
Besides the "programming language" itself, just take a look inside
php.ini. What's that, you ask? It's a global PHP configuration file. Yeah, that's right: the behavior of every PHP script on your entire server can be dictated by a single configuration script. Aren't config files supposed to be a part of, oh I don't know, applications? Content management systems? And not as part of a programming language itself?
On one hand this explains why a lot of free web hosts allow you to use PHP but not Perl; PHP can be neutered and have all of its potentially risky functionality taken away by carefully crafting your php.ini whereas Perl, being a REAL programming language, can't be controlled any more easily than a C binary can. But on the other hand, just look inside php.ini -- there's options in there for how PHP can send e-mails, and how it would connect to a database by default. It even breaks down the databases by type - MySQL, PostgreSQL, MSSQL, etc. Shouldn't database details be left up to the actual PHP code? Apparently not.
So there you have it. I'll never use PHP. It's not even a real programming language. Just a toolkit for rapidly getting a website up and running. What's another name for that? Oh, a Content Management System. Doesn't a PHP CMS sound redundant now? ;)
I got to the office and checked my e-mail and saw that TekTonic (my web hosting company) forwarded an e-mail to me that was sent to their abuse department from another sysadmin, saying that my server's IP has been caught brute-forcing SSH passwords on their server.
So I logged into my server to check things out. My guesses at this point were either: somebody on my server has a weak SSH password, and one of those automated password-guessing bots has cracked it and their account got pwned; or else somebody on my server had something insecure on their site, such as a PHP app or some SSI code, that got compromised and used to attack my server.
After pruning the SSH logs and seeing nothing suspicious, I noticed that the Apache web service was down (so all sites on the server were offline). Apache's been doing this at random intervals so I didn't think much of it just yet and started Apache back up, and then thought to check its global error log file.
Apart from the usual errors that Apache logs here (404 Not Found, etc.) there was other text in the log file that was the output of some commands that would be run at a terminal. Commands like
wget (to download files off the Internet),
chmod (there were some errors like "chmod: invalid mode 'x'" indicating a badly entered chmod command), and
perl (attempting to execute a Perl script).
From reading this in the error log it became apparent that somebody was causing Apache (or at least the user that Apache runs as) to execute system commands. With that, they downloaded a tarball containing exploits from a Geocities site, a tarball containing a backdoor/trojan, and a tarball containing something that they used to "phone home" - probably to make the process of entering commands on my server easier.
In Apache's access log file I was able to see how they were doing this; they were abusing a flaw in phpMyAdmin that allowed them to execute these commands. So, I was right: somebody had a PHP application on their site and this app was used to break into the server. But that somebody was me. :(
So, I was able to see what HTTP requests they were making that was causing phpMyAdmin to execute their commands, and therefore I was able to see all the commands they entered -- or rather, the ones they entered by abusing phpMyAdmin. If the phone home script was indeed used to execute additional commands, they could've run even more after that point (I'm assuming they did, because the initial e-mail I got was about my server guessing SSH passwords on another, and nothing that happened through phpMyAdmin was responsible for that).
I later found out from TekTonic that when they first got the complaint they logged in and killed the Apache-owned process that was brute forcing the SSH passwords. This would explain why Apache was down when I logged in. But the fact that this hacker was running additional commands through the backdoor script that I have no logs of made me decide that reimaging the server would be the best solution. I used to work at a web hosting company and when a customer server got pwned, reinstalling the operating system was the only way to be sure no rootkits were left behind -- especially considering that rootkits these days are pretty crafty and can hide from being listed in the running processes.
I e-mailed the abuse departments at Geocities telling them that one of their users is hosting backdoors and the abuse department of the ISP that controls the IP address of the hacker who broke into my server. Hopefully further action will be done on their parts. The hacker probably won't be found (hackers tend to go through proxy servers like there's no tomorrow), but hopefully whatever server that IP address belongs to can be fixed to prevent further use by the hacker to attack other servers.
This is why I don't like PHP. The exploit in phpMyAdmin was because phpMyAdmin has a PHP file that directly runs system commands based on a query string parameter. This file isn't meant to be executed directly (it's named with a ".inc.php" extension, indicating it was intended to be included by another PHP script and not run directly over the web). But this file was available directly over the web, AND it accepted query string parameters, AND executed those on the system. Terrible! In Perl this kind of thing would never fly. If you did request a Perl included file directly, it wouldn't read your query string parameters, because normally the Perl script that includes it would've done that already.
PHP has too many newbies, and newbies write terrible code. phpMyAdmin could've been smarter than this, but the fact that this happens shows that phpMyAdmin wasn't coded very well at all, probably because its coders are incompetent PHP kiddies.
Anyway, this time around, PHP is NOT installed on my server AT ALL. And if anybody on my server asks for it, to get something like WordPress installed for instance, I'll just kindly point them to MovableType as a Perl alternative to WordPress. WordPress might be a decent PHP application, but it's still a PHP application and I officially will not trust any PHP app written by anyone other than real programmers to be installed on this server again.
PHP programmers who only program PHP basically can be assumed to be completely incompetent and to build in gaping, shameless security holes like what phpMyAdmin had: a script that directly sends query string parameters into a system command unfiltered. PHP programmers who know other programming languages that aren't as newbish as PHP (Perl, for instance) are probably better at coding secure PHP, but besides that I am officially boycotting PHP coders and their applications.