Teaching the TeachersTuesday, July 11. 2006Tuesday, July 11. 2006 Recently the existance of the OWASP PHP Top 5 List was announced in several places. After I read it I was shocked about it's content and immediately asked OWASP who is responsible for it, and that I am shocked about it's content (especially the blatant advertisement in it).
The problem I want to elaborate here is placed in P3 of the OWASP article, where the topic SQL Injection is discussed. The section starts with the following statement: SQL injection is one of the oldest attacks against web I fully agree with this sentence. I even agree with the list of methods that follows, although I cannot accept, that prepared statements are considered more secure than the use of mysql_real_escape_string(). If both techniques are used correctly they are both secure. (Unless there is a security vulnerability in their implementation). So far so good... The section continues with some statements or personal opinions that you can agree or disagree... The article gets interesting however when OWASP describes how to defend against SQL Injection. They present two examples, one using prepared statements and one using just escaping and number conversion functions. When I read it the first time, I was not prepared for the shock I got. I have seen a lot of very bad code during my years of auditing but I have never seen such a scary security hole in security teaching material before. (Well not true, I have disclosed similiar scary holes in the advertised sources of this article...) Let's start with the SQL statement they wanted to protect. (The point of origin is not mentioned in the article). $sql = "SELECT * FROM ". If you are unfamiliar with SQL Injection all you need to know here is that manipulation of the parameter $themeid or by changing the POST variable DBHOST_TBL_PREFIX it is possible to influence what SQL query is executed on the server. This can lead in this example to information disclosure. (Actually, beside the fact that it is a stupid idea to give the user the chance to influence the tablename at all, some SQL purists will also criticize the use of * instead of listing the required fields) Now I will present the offical OWASP solutions to this problem to you. You will find both examples that follow in their PHP Top 5 List. Well until they get removed. Do not use them, they are dangerous.
$sql = "SELECT * FROM “. Solution 2 - Using prepared statements $sql = "SELECT * FROM “.
Corrected Solution $sql = "SELECT * FROM “. The corrected solution is now SQL injection safe up to the degree that was intended by the query designer. Please keep in mind, that I strongly disagree with giving the user the right to choose what table prefix he wants through a POST variable. Depending on the database design, this could result in further information disclosure if it is possible for the attacker to specify a tablename he should not have access to. Additionally it is trivial to supply a name to a nonexisting table. This could trigger an SQL error, that depending on the configuration is printed into the output.
Comments
Display comments as
(Linear | Threaded)
#1
Anonymous
()
IMHO the only sane thing to do if one really wanted to allow tablenames provided by the user, is to check them against a whitelist of safe tablenames.
Though I agree, it makes my brain hurt that somebody thinks using the escape function on the table-name will somehow, magically make things safe. It reminds of the people that half-assedly re-implement prepared statements in PHP and somehow think that the problem of checking for valid Syntax and preventing abuse, and escaping values goes magically away all by itself, because they now use function calls. posted on Tuesday, July 11. 2006
Hey Anonymous,
you are perfectly right. Actually I guess this code was used as demonstration because a similiar code seems to be in FudForum2. In an installer it makes sense, that at some point the user decides what tablename prefix he wants for his bulletin board. Actually I wonder If whoever took this example notified Ilia, or if this example was simply taken to discredit him. I don't know the original intention but I don't believe in coincidences. There are sooo many examples for vulnerable PHP scripts. Why choose code from another author of a book about PHP security? Unfortunately using this example to present "How to Defend against SQL Injection" has backfired on the OWASP author and his reviewers. posted on Tuesday, July 11. 2006
If the example was used to discredit Ilia, it has been done in a very malicious way. The installation script of FUDForum contains following code before first use of $_POST['DBHOST_TBL_PREFIX'] thus is perfectly correct:
if (empty($_POST['DBHOST_TBL_PREFIX']) || preg_match('![^A-Za-z0-9_]!', $_POST['DBHOST_TBL_PREFIX'])) { seterr('DBHOST_TBL_PREFIX', 'SQL prefix cannot be empty or contain non A-Za-z0-9_ characters'); } posted on Wednesday, July 12. 2006
That code looks like it comes from a package installation procedure which is intended to be used by the administrator one time. I think if you have to protect yourself from people installing scripts onto your server than SQL injection is the least of your worries.
It's just a bad example... posted on Tuesday, July 11. 2006
#2.1
Stefan Esser
()
Aaron,
code like this does not only exist in installers. There are a bunch of PHP applications that are vulnerable to tablename prefix injection. However usually that is not the only problem they suffer from. The thing is not, that this is an error. I love the rasmus quote about my favourite "friend": everyone is wrong at some time, but I don't trust a security person/group that has errors in such basic examples The thing is, this is an obvious error. And according to the author this article was reviewed by lots of people. The examples are the most important thing in teaching. If you need to concentrate on something during review, then it is THEM. posted on Tuesday, July 11. 2006
#3
Anonymous
()
Ok, so assuming MySQL < 5, or > 5 with ANSI_QUOTES off would using something like
function quoteName($name) { return '`'.str_replace('`', '``', $name).'`'; } be safe? posted on Tuesday, July 11. 2006
#3.1
Stefan Esser
()
David,
it is always a bad idea to try to guess how certain chacters affect a database. Someone could inject an ASCIIZ char into the table name, which could result in a bad query. Someone could inject a wrong table name (like in the examples above) and still cause SQL errors. You should consult the documentation of the database type that you use. If it says that multibyte charsets for tablenames are allowed, then your code is not safe. If only single byte charsets are allowed for tablenames then it is not possible to break out. If I recall correctly MySQL allows specifying multibyte tablenames. -Stefan posted on Tuesday, July 11. 2006
#3.1.1
Jared Williams
()
Yes, I did suspect multibyte tables names might cause problems. Rather unfortunate my request for a quoteName method in PDO got rejected, given how common using dynamic table names appear to be.
[ http://pecl.php.net/bugs/bug.php?id=3442 ]. Given the popularisation of ORMs, (ActiveRecord and such) and therefore dynamic SQL statement building, I feel PHP/PDO/.. should provide more assistance. PS. Using any values for table names that originate from the client is just plain dumb, and bad design, imo. PS 2. Name isn't David btw posted on Tuesday, July 11. 2006
#3.1.1.1
Stefan Esser
()
Hey Jared,
I called you David, because I dislike calling people Anonymous and infact the IP you used was logged several times in combination with a guy ususally posting as David. You must always keep in mind, that this code according to OWASP was ripped from an installer script. In an installer script it is normal to give the user the oppurtunity to supply a self choosen table prefix name. And unfortunately the prefix is not uncommon and in some applications that use a register_globals emulation (something like extract($_POST, EXTR_OVERWRITE)) it was possible to inject through the table prefix. IIRC phpproject was one that suffered this problem until a complete audit was performed on it. posted on Tuesday, July 11. 2006
#3.1.1.1.1
Jared Williams
()
I really don't see the need for using custom table prefixes. A fixed application specific prefix should be enough to allow several applications to share the same database. I know alot of applications do it, but just seems completely unnecessary.
PS. I presume that's a proxy IP, because my IP has been mine for some time, and I know no Davids'. posted on Wednesday, July 12. 2006
They do have a paragraph in there about this topic (mentioing whitelisting), just not a code example:
"Validate data for correct type, length, and syntax. Always prefer white listing (positive validation) data over black listing, which is akin to virus patterns – always out of date, and always insufficient against advanced attacks" posted on Tuesday, July 11. 2006
#4.1
Stefan Esser
()
Nice try enygma,
the excuse: "We assume that the person has filtered the data beforehand" does not count. In their example they use the mysql escaping function. If they had filtered dangerous chars from user input they would not use the escaping function. Using the escaping function on a table name is simply WRONG. You cannot twist this fact. posted on Tuesday, July 11. 2006
#5
Davey Shafik
()
*ATTENTION: "The following comment was submitted anonymously. However several people verified that the IP used is the one of Davey Shafik. Because he belongs to a group of trouble makers I filled in his name for him."*
"However, as usual it is my duty to protect the PHP community from getting harmed by their self-proclaimed teachers." - And I guess you are annointed by God as opposed to self-proclaimed? Whatever. This was an //EXAMPLE//. Your solution with preg is just as flawed, by using a tablename that doesn't exist, we can still elicit (possibly) some information disclosure. As mentioned, the only true solution is a whitelist of allowed values. Why must you continually attack Chris and others who are at the very least making developers *think* about security? Unlike Hardened PHP which makes them slack off IMNSHO. posted on Tuesday, July 11. 2006
#5.1
Stefan Esser
()
Send me your address, I will send you some money for a reading course.
I exactly wrote, that allowing the table name to be user supplied is bad and allows information disclosure. And well... You have obviously no clue about my contributions to the PHP source code, the countless of security holes I fixed in it. This is protection. You don't protect people by teaching them examples that when used leave them vulnerable. A false sense of security is worse than no security at all. If pointing out security holes to people is attacking them in your way of thinking then you are reading the wrong blog. Ohh btw... You obviously misunderstand Hardened-PHP. It is not meant to help developers, but to protect SERVERS. You obviously have trouble reading documentation, too. posted on Tuesday, July 11. 2006
Well... an anonymous comment. We like that. Davey, is that you?
However, back to the matters at hand: As Stefan pointed out, you seem not to have the slightest clue about what the Hardened-PHP Project actually is and does. Not only are we releasing and maintaining the Hardening Patch (which made the PHP core think about a thing or two, things that have now been put into mainline PHP), we also publish advisories on PHP and application security flaws - both of which I don't see coming from OWASP or Chris Shiflett. All I can see - and I'm not even an anti-Shiflett zealot as Stefan might be - is some genuine content and a lot of marketing. I disapprove of that. Another thing that the Hardened-PHP Project does is continuously stepping on PHP developers' feet by a constant stream of highly specialized and fact-filled sessions at conferences all over Europe. Just ask any attendant of the PHP Vikinger about my talk on application-independant security, or check back with the people who were at WebTech 2006 in Bulgaria - I have received consistently excellent grades for my session at that event. We'd love to come to the US or Canada in the near future. I'd also like to know what *your* contribution to PHP security was and why you think your opinion might not be that humble after all. If you have the courage to post obviously ignorant comments in a public place, why not be courageous enough to sign them with your own name? Generally, I very much approve of OWASP and OWASP's general idea. At once point, Peter and me even contacted Andrew to help out with the PHP chapter - we couldn't though, due to extreme time restrictions surrounding our first book, the 300-page german PHP security book. I'm really sorry for that. What disturbs me is the publication of obvious security holes in a supposedly high-profile documentation as the PHP Top 5 of OWASP, and at the same time, the obvious bias towards specific persons. Why does it matter to the reader *who* says that XSS is evil? It is evil, period. Namedropping is uncalled for in a supposedly objective and well-rounded article in a neutral medium. To sum things up, the usual rule applies: think before you write. posted on Tuesday, July 11. 2006
#6.1
Stefan Esser
()
Sorry, but your reply sounded like:
They already mentioned that you have to do this, so they do not need to put it into the example. posted on Tuesday, July 11. 2006
#7
Anonymous
()
Nope, just stating fact.
Be careful with personal feelings - don't assume that what you think someone's motive is is always the case. posted on Tuesday, July 11. 2006
#7.1
Stefan Esser
()
Sorry Enygma,
my previous blog entries about errors in documentation often resulted in people commenting that "the author just took a wrong example" and that all the rest is true. The problem with that thinking is, that people learn by examples. If they read a book they will read and forget. But the examples in the book they will read again and again to learn how to do it right. -Stefan posted on Tuesday, July 11. 2006
Take a chill pill Stef.
You always seem to get defensive when people comment about you, not that I blame you, you do have a bit of a reputation that people tend to rely on rather than seeing how you really are. BTW: I have read more stuff by you than Chris S. (not that it's a competition) and that you really do make people **think** about security in PHP, through controversy or otherwise. Peace. PS: This captcha image is crap... I can't read it for the life of me. posted on Tuesday, July 11. 2006
#7.1.1.1
Stefan Esser
()
The image is not only hard to read, it is also very easy to break.
For now it has done it's job. But this whole crappy blog will be redesigned soon anyway. The layout is ugly and buggy... God, I wish my day had 48h. posted on Tuesday, July 11. 2006
Drink lots of Bio Plus
posted on Tuesday, July 11. 2006
#8.1
Stefan Esser
()
I was just explaining to you, why I reacted defensive to your first comment. And to explain to others, why I absolutely cannot stand insecure examples.
I remeber a talk by Christian Wenz. If I remember correctly he was talking about people believing that examples how things are wrong shouldn't be in books at all, because people tend to copy and paste without reading/understanding the context. posted on Tuesday, July 11. 2006
IMHO - instead of flamewaring each other over blogs maybe you guys should drink some (more) beer together at the next upcoming php conference. I'll pay the drinks if we meet each other
posted on Tuesday, July 11. 2006
Hi Stefan,
Good article, it seems I wasn't the only one to be suprised by it. Next to the facts you mention in your blog I oppose agains hunting people to upgrade to 5.x as soon as possible. Some companies just can't do that in a short time. As for db security I have another remark. A while back I discussed an idea with the Zend guys on a private list about using seperate db privileges for different users. A. anonymous users should only have select rights on some tables. B. a user could have update, insert permissions as well on some tables ... etc.... It is my beleive that it will not prevent sql injections but at least will limit them to a certain level. Now if people could only learn to think about how and what they code.. I will try to work this out before the summer camp conference in Holland (August) and put the sheets up by then. posted on Tuesday, July 11. 2006
#10.1
Jared Williams
()
Or even better if using MySQL 5, put all the SQL in stored procedures, and then give appropriate execution permissions to the differing users.
Then can revoke all permissions on the base tables for all users. posted on Wednesday, July 12. 2006
right, OWASP guide is broken but I wonder if a guide written by you will be available in the future .. so others can rant about it too..
posted on Tuesday, July 11. 2006
[whoop]
WHAT A GREAT NEW!!! [/whoop] It would also be great if it was free documentation (regardless of cost). If so, I'd be pleased to help in an Spanish translation. -G posted on Wednesday, July 12. 2006
I can hookup subversion access and trac for this.2
posted on Thursday, July 13. 2006
All I can say is nice catch. I'm still trying to figure out how it was missed during a review - three reviewers and the penny still didn't drop? There's not exactly a lot of code in the article to read over. The name dropping is unfortunate when related to issues for which there are numerous people (one would desperately hope) well aware of and indeed handling them on a daily basis. If anything it suggests there are one stop experts - blatantly false obviously. Not here to rant...
Kudos for catching it posted on Tuesday, July 11. 2006
Stefan,
thanks for taking the time out to dissect a problem in our article. That's all we wanted. I will fix the PHP Top 5 article on the OWASP website and reference this post to ensure you are fairly attributed for the fix. This is how we as a security community get better - by accurate peer review from acknowledged specialists. Slanging matches, private or public, do not achieve this. Andrew * The code you dissect comes from FUDForum2's installer, which is noted in the existing text. posted on Wednesday, July 12. 2006
I've corrected the SQL injection examples with code from my own project (XMB -> UltimaBB) rather than just any old random code, referenced this blog entry to provide appropriate attribution, and made changes as appropriate re: table names (as my replacement duff code does not use them in the same way).
I'd really appreciate it if that section could be re-read and evaluated for the updated information it contains. This is how peer review works. (FWIW, I didn't realize that FudForum2's author was an author of any security books. I just grabbed a random bug from Security Focus' vulnerability library (http://www.securityfocus.com/bid/), a bug I knew had been fixed. I do not just go around quoting new bugs in a major piece like this - that's not fair to anyone and not responsible and yet demonstrates my major point - even advanced and skilled authors make basic security mistakes. Me included.) posted on Wednesday, July 12. 2006
This is the least venal post I've seen from you. It's nice to see you making the arguments without resorting to personal attacks (in public anyway).
It's disappointing that organisations like OWASP and PHP Security Consortium, whose stated and implied goals are most laudable, fall into an almost comatose state -- if their websites are any indication. The use of Mediawiki by OWASP and the posting of some articles is the first new thing for some time. This is, of course, a separate question from whether or not the articles contain misinformation or illustrate bad practice (and whatever claims might be made about that -- and of course you've made a number of posts on the very subject). posted on Wednesday, July 12. 2006
#16
Laura Thomson
()
Just to clarify: I did not review this article, and am not cited as having done so anywhere that I can see, so I'd appreciate it if you'd correct your blog entry.
However, I do know Andrew Van Der Stock well, and have had many interesting discussions re web application security with him. I note that he has both incorporated your feedback into the article and thanked you for it. posted on Thursday, July 13. 2006
#16.1
Stefan Esser
()
Laura your name was mentioned in private mail and in Andrew's blog attack on me.
I have now "removed" you from the list. posted on Thursday, July 13. 2006
#17
Amit Klein
()
Stefan,
You write: "the article was, according to it's author reviewed by Amit Klein [...]. It is up to my audience to decide what they think about these people after reading the rest of this blog entry..." In your text, you point at a problem in the SQL injection section of the paper. Yet the OWASP PHP Top 5 says: "The author, Andrew van der Stock, had the article peer reviewed by: [...] Amit Klein (only the XSS section), 13th of October 2005. Updated XSS section to include DOM injection." Meaning I (Amit Klein) did not review the SQL injection section. So I don't see why I'm mentioned in such manner in your text. Thanks, -Amit posted on Sunday, July 30. 2006
#17.1
Stefan Esser
()
Amit,
I will now strike out your name, too. The thing is that Andrew claimed to me, the whole article was reviewed by a bunch of big names. After I pointed out the hole he suddenly removed and changed nearly all of the reviewer names. With your name also gone from the list this leaves only one name. Readers of my blog will see the irony... posted on Sunday, August 6. 2006
The "Solution #1" outlined in the article
mysql_real_escape_string($_POST['DBHOST_TBL_PREFIX']); has yet another flaw. The mysql_real_escape_string() works by considering the character set of the connection when performing the escaping procedure. Which means that to work properly it needs the connection resource to be passed to it. When it is not, it just uses a default one, which would pose a problem in situations when there are multiple connections. In those instances some special characters particular to a given character set may end up being left un-escaped. While this is certainly a fringe case, given that this is training guide, these things need to be considered. posted on Friday, August 4. 2006
Add Comment
|
Calendar
Archives Categories Syndicate This Blog |
|||||||||||||||||||||||||||||||||||||||||||||||||



