0

This question gets asked a lot, but I still haven't found a straight answer on stackoverflow. Are these two functions sufficient or not? There are a lot of contradictory comments around the internet "yes its fine?, "no, never use it". Others say, use PDO, which I don't understand. I'm just a beginner to PHP, so I don't fully understand all of the ins and outs of security. I've tried reading and understanding the following, but many don't make much sense to me.

http://ha.ckers.org/xss.html
Do htmlspecialchars and mysql_real_escape_string keep my PHP code safe from injection?

What if I use preg_replace to strip unwanted characters?

I'm incredibly confused and don't know where to start.

EDIT: Could someone please also recommend how I go about understanding prepared statements (assuming this is the best option).

Community
  • 1
  • 1
Sam
  • 1,564
  • 4
  • 23
  • 37
  • 3
    You may find this a good intro into the whole issue: [The Great Escapism (Or: What You Need To Know To Work With Text Within Text)](http://kunststube.net/escapism/) – deceze Jan 31 '12 at 06:59
  • What I really find helpful quite often: Just type convert input variables to number if you describe an ID or something like that (e.g. when deleting an entry, your url might look like `delete.php?id=100`): `"DELETE FROM table WHERE id = " . (int)$_GET['id']` and you're safe, since Strings will automatically treated as zero. Surely you could also add a simple `if(is_numeric($_GET['id'])) ...` statement. – tim Jan 31 '12 at 07:38
  • Nice suggestion Alexandrew, I will remember it for if it ever applies. At the moment I am adding user input into a database however. – Sam Jan 31 '12 at 07:48
  • 1
    mysql_* is considered pretty much obsolete. Switch to PDO or mysqli – GordonM Jan 31 '12 at 08:41
  • May I ask why you removed the link? – Sam Jan 31 '12 at 21:46
  • because he is writing the same nonsense as others, he actually understands nothing of security and of sql security in particular. – Your Common Sense Feb 01 '12 at 07:27
  • I really have no idea who to trust now. I might just read a book and then learn the hard way, experience. – Sam Feb 02 '12 at 09:43

3 Answers3

2

Sam, if you are storing the input in a database, to avoid SQL injection and XSS then those two functions are enough. If you are storing passwords, you must encrypt the passwords with one-way encryption (that is they can not be decrypted).

Let me expand my answer: First of all, SQL Injection is a method where a malicious user will attempt to modify your SQL statement to make it do their will. For example, let's say you have a login form. By inserting one of the following values into an un-protected form, I will be able to log into the first account without knowing the username or password:

' or 1=1 -- 

There are many versions of the above injection. Let's examine what it does to the SQL executed on the database:

The PHP: mysql_query("SELECT * FROM users WHERE username='" . $username."' AND password='" . $password . "';");

When the above is executed, the following SQL is sent to the database:

SELECT * FROM users WHERE username='' or 1=1-- ' AND password='' or 1=1--';

The effective part of this SQL is this: SELECT * FROM users WHERE username='' or 1=1

as the double dash (with the space afterwards) is a comment, removing the rest of the statement.

Now that gives the malicious user access. With use of an escaping function such as mysql_real_escape_string, you can escape the content so the following is sent to the database:

SELECT * FROM users WHERE username='\' or 1=1-- ' AND password='\' or 1=1--';

That now escapes the quotes, making the intended strings, just that - strings.

Now let's view some XSS. Another malicious user would like to change the layout of a page. A well known XSS attack was the Facespace attack on Facebook back in 2005. This involves inserting raw HTML into forms. The database will save the raw HTML and then it will be displayed to users. A malicious user could insert some javascript with use of the script tag, which could do anything javascript can do!

This is escaped by converting < and > to &ltl; and > respectively. You use the html_special_chars function for this.

This should be enough to secure normal content on a site. However passwords are a different story.

For passwords, you must also encrypt the password. It is advisable to use PHP's crypt function for this.

However, once the password is encrypted and saved in the database as an encypted password, how can you decrypt it to check that it is correct? Easy answer - you don't decrypt it. HINT: A password always encrypts to the same value.

Were you thinking 'We can encrypt the password when the user logs in and check it against the one in the database', you are correct...

Shane
  • 2,007
  • 18
  • 33
  • Thanks for the answer, just one question. Would it be better to used MD5 or SHA2 to hash the passwords rather than encrypting the password? – Sam Jan 31 '12 at 07:34
  • Sam, I would not recommend either method. I would recommend PHP's crypt function. Anyone can create a rainbow table in 2-3 days then crack the md5 in a matter of seconds, but because the crypt function uses a salt, the only possible way of cracking is via brute force. – Shane Jan 31 '12 at 07:39
  • "Rainbow tables are easy to beat. For each password, generate a random number (a nonce). Hash the password with the nonce, and store both the hash and the nonce. The server has enough information to verify passwords (the nonce is stored in the clear). But even with a small random value, say, 16 bits, rainbow tables are infeasible: there are now 65,536 “variants” of each hash, and instead of 300 billion rainbow table entries, you need quadrillions. The nonce in this scheme is called a “salt”." -- from http://bit.ly/18wCf2 – Shane Jan 31 '12 at 07:40
  • Sorry for all the comments - character limit :P Last night I actually did a test on the hashing functions md5, sha1 and crypt. Here are my results:http://img29.imageshack.us/img29/2149/74108984.png – Shane Jan 31 '12 at 07:43
  • Interesting, but I don't really understand how it is stronger. How would you be able to create a rainbow table quickly if a unique salt is generated for each password? Generating a salt for MD5 and SHA2 that is. – Sam Jan 31 '12 at 07:58
  • The speed required to generate the hash is much much slower. If you looked at the image supplied, you will see that 99.57% of the time hashing the same string was spent in the crypt variable. Brute force involves generating a random string, hashing it then comparing it to the hash. If one hash function takes longer to hash than another, it will take much much longer to generate 10 hashes than it would to generate 10 hashes with the other function. – Shane Jan 31 '12 at 08:02
  • Thanks for clearing it up. I looked at your pie chart but I didn't see the benefits. I do now. – Sam Jan 31 '12 at 08:14
  • No worries. Always remember that a slow encryption method is a good encryption method :) – Shane Jan 31 '12 at 08:17
  • @Sam as for your question here, no hashing algorithm will improve security of the **weak password**. As long as your password is just 1234 or joe or similar, it will be broken in seconds despite of super-huge-extra-secure algorithm of hashing. And as long as your password is strong, consists of 10+ different case letters, numbers and punctuation, or even better not a password but a *passphrase*, even weakest hash will be enough. And noone will be able to "create a rainbow table in 2-3 days then crack your password in a matter of seconds". – Your Common Sense Feb 01 '12 at 07:47
0

Depends on what you're using the input for and where it's going.

the only thing to assume when sanitizing input for php applications is that there are a lot of smart people out there, and if they really wanted to break your app, they'll find a way to do it.

following the guides you listed and other guides are a great start. but then every bit of sanitizing you do will incur a non-trivial amount of time and memory to perform.

so it all really depends on what you're using the input for and where it's going.

mysql_real_escape_string and html_special_chars are nice utilities, but you shouldn't depend solely on them and they're are also not always needed.

don't get discouraged as even mature and well programmed sites have to keep up with the latest in xss and other attacks. fun game of cat and mouse.

one place you can start is with a framework, i like codeignitor. go through their security classes to see how they deal with it.

or better yet, write a simple form processor and try to come up with ways to run arbitrary code yourself. you'd be surprised with how many ways you can come up with.

pxl
  • 1,297
  • 10
  • 16
  • 1
    "...should not depend solely on them"? Can you demonstrate a bug in these functions that would cause them to not escape values correctly, assuming *these functions are applied correctly*? – deceze Jan 31 '12 at 07:27
  • if you're using mysql_real_escape_string and only this, then you're giving yourself a false sense of security. http://stackoverflow.com/questions/2353666/php-is-mysql-real-escape-string-sufficient-for-cleaning-user-input – pxl Jan 31 '12 at 07:34
  • an article from the question in my comment above demonstrates how mysql_real_escape_string can be compromised: http://ilia.ws/archives/103-mysql_real_escape_string-versus-Prepared-Statements.html – pxl Jan 31 '12 at 07:38
  • 1
    I knew you'd be posting some link like that. Unfortunately the only answers in there that can clearly show a problem with `mysql_real_escape_string` is if the function is applied *inappropriately*. Either by switching the connection encoding in the wrong way or by not wrapping the values in quotes in the query to begin with. I have yet to see a real case where a **properly applied** `mysql_real_escape_string` has security problems. – deceze Jan 31 '12 at 07:40
  • Mind you that prepared statements are certainly better, but the supposed security flaws so far all stem from a misuse of the function, rather then from a real bug in the function itself. – deceze Jan 31 '12 at 07:41
  • googling around for any real examples, and you're right that there aren't any quick to find examples of real case compromises due to mysql_real_escape_string, but that people can come up with ways it could fail (http://stackoverflow.com/questions/5741187/sql-injection-that-gets-around-mysql-real-escape-string) would lead me to recommend one of the points in your escapism article: to use prepared statements. – pxl Jan 31 '12 at 07:51
  • what article you are talking about? – Your Common Sense Feb 01 '12 at 11:22
0

Assuming you are asking about security, there is one problem with mysql_real_escape_string.

This function has absolutely nothing to do with security.

Whenever you need escaping, you need it despite of "security", but just because it is required by SQL syntax. And where you don't need it, escaping won't help you even a bit.

The usage of this function is simple: when you have to use a quoted string in the query, you have to escape it's contents. Not because of some imaginary "malicious users", but merely to escape these quotes that were used to delimit a string. This is extremely simple rule, yet extremely mistaken by PHP folks.

This is just syntax related function, not security related.

Depending on this function in security matters, believing that it will "secure your database against malicious users" WILL lead you to injection.

A conclusion that you can make yourself:
No, this function is not enough.

Prepared statements is not a silver bullet too. It covers your back for only half of possible cases.

Your Common Sense
  • 156,878
  • 40
  • 214
  • 345
  • Sam, mysql_real_escape_string does have something to do with security - securing your database against malicious users executing their own SQL commands. If you have an SQL command "SELECT * FROM users WHERE username='" .$username . "';" with PHP, the user has full control of what goes into username, as you provide them an input field. If they input something like ' or 1=1 -- then they will have 'broken' your statement. What you need to do is use mysql_real_escape_string to escape the quotes - that is turn this ' into this \'. I also suggest you move onto mysqli for better performance. – Shane Feb 01 '12 at 05:36
  • @Sam that's simple. Where you need escaping, you need it despite of security, just because of **SQL syntax** rules. And where you don't need it, **escaping won't help you even a bit.** See? This is just syntax related function, not security related. – Your Common Sense Feb 01 '12 at 07:29
  • Col. Shrapnel, do not tell me I do not know what I am talking about. You obviously do not understand database security enough to know that securing a database is considered 'security'. Securing the database does not make the passwords encrypted if that is what you are saying, it escapes input into the database, preventing malicious users running their own SQL. – Shane Feb 01 '12 at 13:49