SQL 中的转义引号
根据 php.net 我应该使用 mysql_real_escape_string() 并关闭魔术引号,因为它已被弃用。
所以我把它关掉并使用了mysql_real_escape_string(),但是像下面的代码一样使用它就足够了吗?
$value = "It's Time!";
$escaped_value = mysql_real_escape_string($value);
mysql_query("INSERT INTO table (column, column2) VALUES ('{$escaped_value}', "0")");
当我检查数据库中的数据时,它看起来与 $value 中的数据相同,因此是 “It's Time”
而不是 “It\'s Time”
。这是正常的吗?这不应该在引号前添加斜杠吗?
According to php.net I should use mysql_real_escape_string() and turn off magic quotes, because it's deprecated.
So I turned it off and I used mysql_real_escape_string(), but is it enough to use it just like in the following code?
$value = "It's Time!";
$escaped_value = mysql_real_escape_string($value);
mysql_query("INSERT INTO table (column, column2) VALUES ('{$escaped_value}', "0")");
When I check the data in the database it looks the same way as in $value so "It's Time"
and not "It\'s Time"
. Is this normal? Shouldn't this add a slash before the quotes?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这是正确的行为,而且有效!引号是在查询中转义的,而不是在数据库中转义的。 SQL查询中的\'必须在数据库内部转换为'。
您对字符串进行转义,这样 SQL 查询就不会混乱,并且可以将引号输入到数据库,而 SQL 查询不会将它们解释为控制字符。
您的转义查询将是:
您的数据库数据应该是“It's time”。
如果它没有被转义,它将是:
它将吐出一个关于“s time”的错误(因为它只会解释到下一个引号字符,并且只会看到“It”。)和“It's time!”只是一个无害的字符串,但如果您不转义字符,则可能会由此衍生出许多攻击。
That's the correct behaviour, and it works! Quotes are escaped in the query, not in the database. \' in the SQL query must be converted to ' inside the database.
You escape strings, so the SQL query doesn't get messed up and lets input quotes to the database without the SQL query interpreting them as control characters.
Your escaped query would be:
Your database data should be "It's time".
If it weren't escaped it would be:
It will spit out an error regarding "s time'" (because it will only interpret until the next quote character, and will only see 'It'.) And "It's time!" is just an inoffensive string, but lots of attacks could derive from that if you don't escape your characters.
简短回答
这是正确的。
长答案
这是正确的,但你的问题表明你对这里发生的事情缺乏深入的理解。这是您的查询:
让我们看看如果不转义,用户输入以下数据会发生什么:
请记住,您只是将字符串传递给 MySQL,插入是由 PHP 的字符串处理完成的。这意味着在这种情况下,发送到 mysql_query 的查询是:
这是一个语法错误,并且会导致页面错误。现在,当像我这样的用户(即一个想让你的一天变得痛苦的混蛋:D)发现其中一个时,我们知道是时候玩了。如果用户提供以下数据会发生什么?
我们的查询扩展为:
这不是语法错误,但它是有问题的...我们现在正在执行一个我们从未打算执行的查询! (如果您不认识它,“--”表示 SQL 中的注释,即“忽略此点之后的所有内容”)。
现在,在这个确切的实例中,这种情况不可能发生(mysql_query 不支持多个查询< /a>),但这是您试图阻止的攻击类型 - 一类称为 SQL 注入的攻击。让我们看看使用 mysql_real_escape_string 时会发生什么!
输入的数据变成:
这意味着我们的查询字符串看起来像:
Which is Fine!用户输入的数据将在输入时存储在数据库中。不是没有引号,也不是带有额外的反斜杠,而是他们输入的内容。 这很重要。如果您以其他方式存储数据,稍后会遇到反转义或双重转义的问题。此外,添加额外的斜杠或类似的内容通常最终会以某种方式暴露给用户,这是一个巨大的警告信号,表明事情可能无法正确转义。您希望避免做错误的事情,并且您特别希望避免做错误的事情并为此做广告,这将我带入下一部分:
转义数据的替代方法
魔术引号。正如您所指出的,已弃用(并且有充分的理由),请避免。
不要转义你的数据。我建议不要选择这个选项。
从输入中去除坏字符。几乎在所有情况下都很烦人,您应该存储用户输入的内容,而不是技术上易于存储的内容。
禁止输入错误字符。有时可以接受(信用卡号字段不需要处理引号),有时令人讨厌,有时是一个巨大的警告标志(例如在密码字段上时)
准备好的语句。我说过字符串中变量的“填充”是由 PHP 完成的,而 MySQL 只是获取查询字符串,因此需要转义。准备好的语句通过更加智能来减轻这项工作,并且使用准备好的语句看起来像这样(警告:伪代码):
$statement = $db->prepare('INSERT INTO 表(列, 列2) VALUES ("%1", "%2")');
$result = $statement->execute($value1, $value2);
有一个很好的 Stack Overflow 问题,关于 SQL 转义方法和那里的答案更深入,所以你可能想读一下。
就我个人而言,这是我喜欢的选择。您不能忘记转义变量并以这种方式将其插入数据库 - 要么值被正确编组,要么它们不会接近数据库,没有中间选项。也就是说,假设您强制所有查询都经过准备好的语句,并且没有像
Is did 这样的字符串连接。在我看来,这比跟踪哪些变量已清理、哪些变量未清理更容易。有些人喜欢在字符串来自用户时立即对其进行转义,但是如果它们可以转到数据库以外的任何地方(返回到 HTML、内存缓存等),那就非常尴尬了。如果您打算自己这样做,我可能会这样做建议一些匈牙利表示法,例如:
我第一次在一篇优秀的文章中看到这个想法 让错误的代码看起来错误< /a> 作者:乔尔·斯波尔斯基。
结论
希望您现在为制作防注入网站做好了更好的准备。无论您选择哪种方法,祝您好运,并享受确保在所有用户输入到达数据库之前始终转义所有用户输入的乐趣! ;)
Short answer
This is correct.
Long answer
This is correct, but your question indicates a lack of depth of understanding of what's going on here. Here's your query:
Let's see what happens if you don't escape, and the user enters the following data:
Remember that you are just passing a string to MySQL, the insertion is done by PHP's string processing. This means that in this instance, the query sent to mysql_query is:
Which is a syntax error and would make the page error out. Now, when a user like me (i.e. a bastard intent on making your day a misery :D) spots one of these, we know it's time to play. What happens if the following data is supplied by a user?
Our query is expanded to:
This isn't a syntax error, but it is problematic... we are now executing a query we never intended to! (In case you don't recognise it, "--" denotes a comment in SQL, i.e. "ignore everything after this point").
Now this can't happen in this exact instance (mysql_query doesn't support multiple queries), but it's the sort of attack you are trying to prevent - a class of attacks known as SQL injection. Let's see what happens when you use mysql_real_escape_string!
The inputted data becomes:
Which means our query string looks like:
Which is fine! The data the user entered will be stored in the database, as they entered it. Not without quotes, and not with extra backslashes, but as they entered it. This is important. If you store the data any other way, you will run into issues later, with de-escaping or double-escaping. Additionally, adding extra slashes or anything like that often ends up exposed to the users in one way or another, and it's a giant warning sign that things may not be being escaped properly. You want to avoid doing the wrong thing, and you especially want to avoid doing the wrong thing and advertising about it, which brings me to the next section:
Alternatives to escaping your data
Magic quotes. As you noted, deprecated (and with good reason), avoid.
Don't escape your data. I would advise against this option.
Strip bad characters from input. Annoying in nearly all situations, you should store what users enter, not what's technically easy to store.
Disallow bad characters from input. Sometimes acceptable (credit card number fields don't need to handle quotes), sometimes annoying, sometimes a massive warning sign (when on a password field for example)
Prepared statements. I said that the "filling in" of variables in the string was done by PHP and MySQL was just getting a query string, hence the need for escaping. Prepared statements offloads this work by being a little more intelligent, and using a prepared statement would look something like this (warning: pseudocode):
$statement = $db->prepare('INSERT INTO table (column, column2) VALUES ("%1", "%2")');
$result = $statement->execute($value1, $value2);
There's a nice Stack Overflow question on SQL escaping methods and the answers there go into more depth, so you may want to read that.
Personally, this is the option I like. You can't forget to escape a variable and insert it into the database this way - either values are properly marshalled, or they don't get anywhere near the database, there is no halfway option. That is, assuming you enforce that all queries go through prepared statements, and no string concatenation like
Is done. In my opinion, this is easier than keeping track of which variables are sanitized and which are not. Some people like to escape strings as soon as they come from the user, but that's very awkward if they could go anywhere other than the database - back into the HTML, into memcache, etc. If you are going to do it yourself, I might suggest some Hungarian notation, for example:
I first saw this idea in an excellent article Making Wrong Code Look Wrong by Joel Spolsky.
Conclusion
Hopefully you feel better prepared to make injection-proof sites now. Good luck with whichever method you chose, and have fun making sure you always escape all user input before it hits the database! ;)
mysql_real_escape_string() 通常足以防止 SQL 注入。
您还应该过滤从用户那里获得的数值(通过使用 intval())。
mysql_real_escape_string() is usually enough for preventing SQL injection.
You should also filter numeric values you are getting from the user (by using intval()).