1

I know this is quite a popular question and, having researched for many hours now, I am still a little unsure on a definitive answer. I am no pro at PHP and have been self teaching for a little while now. I have just recently got my head around MYSQLi prepared statements (having been used to the old practice).

My main question is trying to find a definitive answer on the requirement to use real escape string (or any other security) when using prepared statements.

I have ready through the following questions:

Prepared Statements, escape variables

IF I use mysqli prepared statements do i need to escape

Do PHP PDO prepared statments need to be escaped?

But there seem to be arguments for and against escaping data when using prepared statements. There is also a lot of mention of PDO which, for me, is very confusing as I am no genius with PHP.

I am looking to this great community to help me understand completely and give me an answer (in a way I hopefully understand) in order for me to progress.

To that end, I have the following examples and ask if someone could, in lay-mans terms, explain which to use, which not to use and more importantly, WHY?

I am currently using this throughout my code:

$id = $conn->real_escape_string($_POST['id']);
$name = $conn->real_escape_string($_POST['name']);
$message = $conn->real_escape_string($_POST['message']);

$qry = $conn->prepare('INSERT INTO status (id, name, message, date) VALUES (?, ?, ?, NOW())');
$qry->bind_param('iss', $id, $name, $message);
$qry->execute();
$qry->close();

But, my limited understanding of the example questions above is telling me that it is safe/ok to use the following code:

$qry = $conn->prepare('INSERT INTO status (id, name, message, date) VALUES (?, ?, ?, NOW())');
$qry->bind_param('iss', $_POST['id'], $_POST['name'], $_POST['message']);
$qry->execute();
$qry->close();

So, which is the best method? Sorry for the long winded question. Having researched it and trying to understand it I just want to be sure and understand the reasons.

Thank you all for your time and support, I would very much appreciate any help provided.

Community
  • 1
  • 1
NOJ75
  • 63
  • 8
  • Unclear as to why someone down-voted this question. I would imagine that there are many out there, like me, who do not fully understand the "coding jargon" and would have appreciated a simplistic answer like the one provided below. – NOJ75 Jan 09 '16 at 10:51
  • without real_escape_string() your query is open for xss try to put in the string fields it save the value in db as it is. – MasoodRehman Jan 09 '16 at 10:53
  • @MasoodRehman sorry, I have not clue as to what you mean. – NOJ75 Jan 09 '16 at 11:02
  • what i mean is it's a good practice to escape $_POST values before add it into db. – MasoodRehman Jan 09 '16 at 15:15
  • Now I am confused as all the answers below are saying that it is not required when using prepared statements. – NOJ75 Jan 09 '16 at 16:52
  • ok if you are using 2nd approach i mean without real_escape_string() POST values then let me know what happen when you input in the name and message input fields and submit the form, is it saved into table as it is or without angle brackets > or <. if it is does not remove the angle brackets or escaping the special characters then your query is not secured and it is open for xss attack. – MasoodRehman Jan 09 '16 at 19:35
  • Yes, I got a javascript alert 1. So what now? Does this mean I need to escape the string? EDIT: I escaped the string but the alert still happened. What is the solution to this problem? – NOJ75 Jan 10 '16 at 09:19
  • I have used the following: $message = preg_replace('##is', '', $message); This removes the script tag and everything between. Is this the only way? – NOJ75 Jan 10 '16 at 09:33
  • I have gone with the following: $message = strip_tags($message, ''); This should be all I need. – NOJ75 Jan 10 '16 at 09:56
  • Ok if you got alert 1 this means your query is vulnerable – MasoodRehman Jan 10 '16 at 16:55
  • You need to make it secure otherwise hackers can insert malicious codes into your db and exploit your database and your application, use php filters to sanitize and validate user inputs and also mysql real escaping strings before insert data into db a good security practice – MasoodRehman Jan 10 '16 at 17:09
  • So strip_tags will suffice to remove this possibility? – NOJ75 Jan 10 '16 at 17:14
  • yes strip_tags or filter_var, The advantage of filter_var() is that you can control the behavior by stripping or encoding here is a list of sanitizing filters http://php.net/manual/en/filter.filters.sanitize.php – MasoodRehman Jan 10 '16 at 17:22
  • Thank you for the info and your time. Very useful. – NOJ75 Jan 10 '16 at 17:24
  • your welcome happy coding :) – MasoodRehman Jan 10 '16 at 17:35

3 Answers3

6

NB: This answer uses an overly-simplistic model of what escaping and prepared statements actually do.

SQL is a language. Some characters in it have special meaning. For instance ' delimits the beginning and end of a string.

When you escape data, you put a \ in front of the characters with special meaning. That causes them to mean (for example) "An apostrophe" instead of "The end of the string".

So:

$id = $conn->real_escape_string($_POST['id']);

So now, if there was a ' in the ID, it won't break the SQL.

When you use a bound variable, it will automatically be escaped for you.

$qry->bind_param('iss', $id, $name, $message);

So now, if there was a ' in the ID, it won't break the SQL.

… except you have already done that.

So now you have the ' turned into \' and then in to \\\' because the ' was escaped and then it was escaped again along with the \ from the first escape.

So now the first \ has been treated as data (instead of as a special SQL character) and inserted into the database.

Use prepared statements. Use only prepared statements.

(The exception is when you are doing things with variables where a prepared statement can't go, such as dynamic table names, which shouldn't be too often).

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • 1
    Thank you so very much for this answer and for your valuable time in posting it. This is exactly what I was after. VERY easy to understand, I now fully understand WHY I do not need to escape. Thank you again! – NOJ75 Jan 09 '16 at 10:48
  • This statement *When you use a bound variable, it will automatically be escaped for you.* is misleading, even wrong. SQL does not escape bound variable values. It treats them as values without parsing them for SQL constructs. – trincot Jan 09 '16 at 11:08
  • 1
    @trincot — Please note the very first sentence of the answer. – Quentin Jan 09 '16 at 11:12
  • @TiagoMedici — There will be no backslash in the retrieved data if it was inserted correctly. – Quentin Feb 18 '23 at 17:43
  • @TiagoMedici — Using a prepared statement will not add slashes to the data. Perhaps you should ask a [new question](https://stackoverflow.com/questions/ask) with a [mcve]. – Quentin Feb 18 '23 at 17:58
1

If you use prepared statements, you definitely don't need to escape parameters using real_escape_string() or any other similar function. In fact, if you escape it, you can end up with double-escaped values.

Your second example is completely valid.

Michał Perłakowski
  • 88,409
  • 26
  • 156
  • 177
1

The answer is stated in the article on Prepared Statements in the PHP docs:

Escaping and SQL injection

Bound variables are sent to the server separately from the query and thus cannot interfere with it. The server uses these values directly at the point of execution, after the statement template is parsed. Bound parameters do not need to be escaped as they are never substituted into the query string directly. [...]

Such a separation sometimes considered as the only security feature to prevent SQL injection, but the same degree of security can be achieved with non-prepared statements, if all the values are formatted correctly. It should be noted that correct formatting is not the same as escaping and involves more logic than simple escaping. Thus, prepared statements are simply a more convenient and less error-prone approach to this element of database security.

(emphasis mine).

Note that a prepared statement is compiled by the database engine before the parameters are bound. It really is the database engine that is capable of executing this query with arguments. At no time is an SQL string created that concatenates the string of the prepared SQL statement with the string version of the arguments.

Think of SQL as a language for us humans. The DB engine on the other hand does not need to have everything worded in a plain SQL string before it can do anything. On the contrary, it needs to parse SQL before it can do anything. So it can work with the two pieces of information (prepared statement, arguments) to produce the desired output without having to first build the complete SQL string. And because it does not build that string, it also does not need to escape anything. The arguments are not parsed again for SQL constructs (which would be the SQL injection risk). They are used as values, nothing more.

Community
  • 1
  • 1
trincot
  • 317,000
  • 35
  • 244
  • 286
  • Thank you for your time. I did see this when researching, but although I can extract that no escaping is required I did not understand the reasons why. This is probably due to my lack of understanding of what bound parameters, parsing etc is really all about. – NOJ75 Jan 09 '16 at 10:39
  • It is because the arguments are not injected into the SQL string, it really is the database engine that takes both the prepared statement and the list of arguments to execute the query. There is no concatenation of strings happening. – trincot Jan 09 '16 at 10:43