直接来自数据库的值是否需要转义?

发布于 2024-12-05 05:59:23 字数 1035 浏览 1 评论 0原文

我是否需要转义/过滤来自数据库的数据?即使所述数据已经被“转义”一次(在将其插入数据库的时间点)。

例如,假设我允许用户通过具有标题输入和文本区域输入的表单提交博客文章。

恶意用户提交了博客文章

title: Attackposttitle');DROP TABLE posts;--

文本区域:哈哈哈,毁掉了你的网站 noobzors!

现在,当它被插入到我的数据库中时,我将使用 mysql_real_escape_string 对其进行转义,但是一旦它进入数据库,我稍后将在我的 php 博客应用程序中引用此数据,如下所示:

sql="SELECT posttitle FROM posts WHERE id=50";
$posttitlearray = mysql_fetch_array(mysql_query($sql));

这就是我关心的地方,什么例如,如果我运行以下查询来获取帖子内容:

sql="SELECT postcontent FROM posts WHERE posttitle=$posttitlearray[posttitle]";

理论上我自己不是在进行sql注入吗?即,我是否没有有效地运行查询:

sql="SELECT postcontent FROM posts WHERE posttitle=Attackposttitle');DROP TABLE posts;--";

或者“Attackposttitle');DROP TABLE posts;--”数据一旦进入数据库就会继续被转义?

我是否需要像这样不断地转义它:

sql="SELECT postcontent FROM posts WHERE posttitle=msql_real_escape_string($posttitlearray[posttitle])";

或者数据在首次插入数据库时​​最初转义后是否安全?

谢谢堆栈!

Do I need to escape/filter data that is coming from the database? Even if said data has already been "escaped" once (at the point in time where it was inserted into the database).

For example, say I allow users to submit blog posts via a form that has a title input and a textarea input.

A malicious user submits the blog post

title: Attackposttitle');DROP TABLE posts;--

textarea: Hahaha nuked ur site noobzors!

Now as this is being inserted into my database, I am going to escape it with mysql_real_escape_string, but once it is in the database I will later reference this data in my php blog application with something like this:

sql="SELECT posttitle FROM posts WHERE id=50";
$posttitlearray = mysql_fetch_array(mysql_query($sql));

This is where my concern is, what if I, for example, run the following query to get the post content:

sql="SELECT postcontent FROM posts WHERE posttitle=$posttitlearray[posttitle]";

In theory am I not sql injecting myself? IE, am I not effectively running the query:

sql="SELECT postcontent FROM posts WHERE posttitle=Attackposttitle');DROP TABLE posts;--";

Or does the "Attackposttitle');DROP TABLE posts;--" data continue to be escaped once it is in the database?

Do I need to continually escape it like so:

sql="SELECT postcontent FROM posts WHERE posttitle=msql_real_escape_string($posttitlearray[posttitle])";

Or is the data safe once it has been escaped initially upon first being inserted into the database?

Thanks Stack!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

鹊巢 2024-12-12 05:59:23

一旦放入数据库,它就不会继续被转义。你将不得不再次逃离它。

$sql="SELECT postcontent FROM posts WHERE posttitle='".mysql_real_escape_string($posttitlearray[posttitle])."'";

It does not continue to be escaped once it's put in the database. You'll have to escape it again.

$sql="SELECT postcontent FROM posts WHERE posttitle='".mysql_real_escape_string($posttitlearray[posttitle])."'";
半岛未凉 2024-12-12 05:59:23

每次插入 SQL 查询之前都应对该值进行转义。不是出于神奇的安全原因,而只是为了确保结果查询的语法正确。

转义这根弦对很多人来说听起来很神奇,就像抵御某种神秘危险的盾牌,但实际上它并没有什么神奇的。这只是让查询能够处理特殊字符的方法。

最好只是看看转义到底做了什么。假设输入字符串是:

Attackposttitle');DROP TABLE posts;--

转义之后:

Attackposttitle\');DROP TABLE posts;--

实际上它只转义了单个斜杠。这是您唯一需要确保的事情 - 当您在查询中插入字符串时,语法将是正确的!

insert into posts set title = 'Attackposttitle\');DROP TABLE posts;--'

这没有什么神奇的,比如危险盾之类的,它只是为了确保结果查询具有正确的语法!(当然,如果不正确,它可以被利用)

查询解析器然后查看\' 序列并知道它仍然是变量,而不是其值的结尾。它将删除反斜杠,并且以下内容将存储在数据库中:

Attackposttitle');DROP TABLE posts;--

这与用户输入的值完全相同。这正是您想要在数据库中拥有的内容!

因此,这意味着如果您从数据库中获取该字符串并希望在查询中再次使用它,则需要再次对其进行转义以确保生成的查询具有正确的语法

但是,在您的示例中,需要提及的非常重要的一点是 magic_quotes_gpc 指令!

此功能会自动转义所有用户输入(gpc - _GET、_POST 和 _COOKIE)。 这是一个邪恶的功能,专为那些不了解 SQL 注入的人而设计。它是邪恶的,有两个原因。第一个原因是,您必须区分第一个和第二个查询的大小写 - 在第一个查询中您不会转义,而在第二个查询中您会转义。大多数人所做的就是关闭“功能”(我更喜欢这个解决方案)或首先取消转义用户输入,然后在需要时再次转义。 unescape 代码可能如下所示:

function stripslashes_deep($value)
{
        return is_array($value) ?
               array_map('stripslashes_deep', $value) :
               stripslashes($value);
}

if (get_magic_quotes_gpc()) {
        $_POST = stripslashes_deep($_POST);
        $_GET = stripslashes_deep($_GET);
        $_COOKIE = stripslashes_deep($_COOKIE);
}

第二个原因是因为不存在“通用引用”
引用时,总是引用某些特定输出的文本,例如:

  1. mysql 查询的字符串值
  2. like mysql 查询的表达式
  3. html 代码
  4. json
  5. mysql 常规expression
  6. php 正则表达式

对于每种情况,您需要不同的引用,因为每种用法都存在于不同的语法上下文中。这也意味着不应在 PHP 的输入处进行引用,而应在特定的输出处进行引用!这就是像magic_quotes_gpc这样的功能被破坏的原因(永远不要忘记处理它,或者更好,确保它被关闭!!!)。

那么,在这些特殊情况下,人们会使用什么方法来引用呢? (请随意纠正我,可能有更现代的方法,但这些对我有用)

  1. mysql_real_escape_string($str)
  2. mysql_real_escape_string(addcslashes($str, "%_"))< /code>
  3. htmlspecialchars($str)
  4. json_encode() - 仅适用于 utf8!我将我的函数用于 iso-8859-2
  5. mysql_real_escape_string(addcslashes($str, '^.[]$()|*+?{}')) - 在这种情况下你不能使用 preg_quote 因为反斜杠将被转义两次!
  6. preg_quote()

The value should be escaped every time just before insertion to SQL query. Not for magical security reasons, but just to be sure that the syntax of the resultant query is OK.

Escaping the string sound magical to many people, something like shield against some mysterious danger, but in fact it is nothing magical. It is just the way to enable special characters being processed by the query.

The best would be just to have a look what escaping really does. Say the input string is:

Attackposttitle');DROP TABLE posts;--

after escaping:

Attackposttitle\');DROP TABLE posts;--

in fact it escaped only the single slash. That's the only thing you need to assure - that when you insert the string in the query, the syntax will be OK!

insert into posts set title = 'Attackposttitle\');DROP TABLE posts;--'

It's nothing magical like danger shield or something, it is just to ensure that the resultant query has the right syntax! (of course if it doesn't, it can be exploited)

The query parser then looks at the \' sequence and knows that it is still the variable, not ending of its value. It will remove the backslash and the following will be stored in the database:

Attackposttitle');DROP TABLE posts;--

which is exactly the same value as user entered. And which is exactly what you wanted to have in the database!!

So this means that the if you fetch that string from the database and want to use it in the query again, you need to escape it again to be sure that the resultant query has the right syntax.

But, in your example, very important thing to mention is the magic_quotes_gpc directive!

This feature escapes all the user input automatically (gpc - _GET, _POST and _COOKIE). This is an evil feature made for people not aware of sql injection. It is evil for two reasons. First reason is that then you have to distinguish the case of your first and second query - in the first you don't escape and in the second you do. What most people do is to either switch the "feature" off (I prefer this solution) or unescape the user input at first and then escape it again when needed. The unescape code could look like:

function stripslashes_deep($value)
{
        return is_array($value) ?
               array_map('stripslashes_deep', $value) :
               stripslashes($value);
}

if (get_magic_quotes_gpc()) {
        $_POST = stripslashes_deep($_POST);
        $_GET = stripslashes_deep($_GET);
        $_COOKIE = stripslashes_deep($_COOKIE);
}

The second reason why this is evil is because there is nothing like "universal quoting".
When quoting, you always quote text for some particular output, like:

  1. string value for mysql query
  2. like expression for mysql query
  3. html code
  4. json
  5. mysql regular expression
  6. php regular expression

For each case, you need different quoting, because each usage is present within different syntax context. This also implies that the quoting shouldn't be made at the input into PHP, but at the particular output! Which is the reason why features like magic_quotes_gpc are broken (never forget to handle it, or better, assure it is switched off!!!).

So, what methods would one use for quoting in these particular cases? (Feel free to correct me, there might be more modern methods, but these are working for me)

  1. mysql_real_escape_string($str)
  2. mysql_real_escape_string(addcslashes($str, "%_"))
  3. htmlspecialchars($str)
  4. json_encode() - only for utf8! I use my function for iso-8859-2
  5. mysql_real_escape_string(addcslashes($str, '^.[]$()|*+?{}')) - you cannot use preg_quote in this case because backslash would be escaped two times!
  6. preg_quote()
断舍离 2024-12-12 05:59:23

尝试使用绑定变量。这将消除完全转义数据的需要。

http://php.net/manual/en/function.mssql-bind.php

唯一的缺点是您只能将它们与 SQL Server 中的存储过程一起使用,而其他数据库则可以将它们用于所有用途。

Try using bind variables. which will remove the need to escape your data completely.

http://php.net/manual/en/function.mssql-bind.php

only down side is your restricted to using them with stored procedures in SQL server, other database you can use them for everything.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文