SQL注入保护
我想我会听取您对一个选项的意见,我认为该选项可以从根本上消除 SQL 注入的可能性(我认为)。
目前,我有我的管理员帐户,这显然让我可以完全控制数据库(更改、删除等)。我有一个 PHP 使用的帐户,它只能访问 SELECT、UPDATE、DELETE、INSERT。为每个操作设置一个用户,然后在 mysql_query 语句中引用连接 ID 怎么样?现在显然这会给服务器带来更大的压力,基本上每页必须建立 4 个连接,但如果安全性是重要的是,在我看来,通过将命令限制为您想要在这种情况下执行的确切功能,这将是一个有效的选项。对这个选项的可行性有什么想法吗?
更新:正如我之前没有提到的,这不会是防止 SQL 注入、mysql_real_escape_string()、准备好的语句等的唯一障碍。但我只是在想,如果通过某种方式,所有这些都失败了,这不是吗?至少限制他们可能造成的损害? (例如,在注册表上,他们将无法选择哈希值或删除条目)。
I thought I would get your opinion on an option I thought that would essentially eliminate the possibility of SQL injection (I think).
Currently, I have my admin account which obviously gives me full command of the database (alter, drop, etc). I than have an account that PHP uses which only has access to SELECT, UPDATE, DELETE, INSERT. What about setting up a user for each of those actions, and then just referencing the connect ID in the mysql_query statement - now obviously this would put a lot more strain on the server, having to make 4 connections perpage essentially, but if it security is important, it seems to me that this would be a valid option, by limiting the commands to EXACT function that you want performed in that case. Any thoughts on the viability of this option?
UPDATE: As I failed to mention earlier, this would NOT be the sole barrier of preventing SQL injection, mysql_real_escape_string(), prepared statements, etc. But I was just thinking maybe if by some how, ALL of these fail, wouldn't this at least limit the damage they could do? (e.g. on a registration form, they would be unable to SELECT hashes, or DELETE entries).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这不是 SQL 注入的全部内容。每当您在 SQL 查询中使用未经清理的参数时,您的数据库就会面临 SQL 注入,这不一定会破坏数据。它还可能窃取数据或获得未经授权的访问。
考虑一个非常受限的帐户,它所能做的就是
SELECT
。您编写一个用于身份验证的查询:使用正常输入,您希望查询如下所示:
如果用户名和密码都匹配,则应返回 1 作为计数。现在,攻击者尝试以管理员身份登录。由于您尚未清理您的输入,因此它们将
$_POST['user']
发送为:admin'; --
。整个查询变成:--
之后的所有内容都是注释,因此忽略其他条件并无论如何返回 1。就这样,您刚刚授予了恶意用户管理员访问权限。一些真正的攻击就是这样进行的。您从一个低特权帐户开始,然后通过安全漏洞尝试获得更多特权。长话短说,拥有一个具有受限权限的应用程序范围帐户(例如:没有
DROP
、ALTER
等)是很好的。切勿给予任何人或任何应用程序超出其需要的权限。但为了防止 SQL 注入,请使用准备好的语句。This is not what SQL Injection is all about. Any time you use parameters that haven't been sanitized in your SQL query you leave your database open to SQL injection, which might not necessarily have the goal of destroying data. It could also be to steal data or gain unauthorized access.
Consider a very restricted account where all it could do is
SELECT
. You write a query for authentication:With normal input, you expect the query to look like:
Which should return 1 as the count if both username and pass match. Now an attacker tries to log in as admin. Since you haven't sanitized your inputs, they send
$_POST['user']
as:admin'; --
. The whole query becomes:Everything after
--
is a comment, so this ignores the other condition and returns 1 regardless. There you go, you've just granted a malicious user admin access. That is how some real attacks are carried out. You start with a low privileged account and through holes in security you try to gain access to more privileges.Long story short, having an application-wide account with restricted privileges (eg: no
DROP
,ALTER
, etc) is good. Never give anyone or any application more privileges than they need. But to prevent SQL injection, use prepared statements.拥有具有有限权限的单独用户是一种常见的做法。但即使您拥有这样的用户,它也无法保护您免受 SQL 注入攻击。
考虑以下示例:
恶意用户可以通过将
post_id
设置为1 OR 1=1
轻松删除您的所有帖子:要获得有效的保护,您应该始终将字符串转义为在查询中使用:
或者更好地使用准备好的语句。
Having separate user with limited privileges is a common practice. But even if you will have such a user, it won't protect you from SQL injection attacks.
Consider the following example:
Malicious user can trash all your posts with ease by setting
post_id
to1 OR 1=1
:To get a valid protection you should always escape strings to be used in a query:
Or better use prepared statements.
这与 SQL 注入关系不大。你说的是用户权限。如果您不清理用户输入并且不将准备好的语句与 PDO 一起使用,那么设置用户权限对于保护您免受 SQL 注入的影响为零。
了解有关 SQL 注入的更多信息:SQL 注入和 PDO
This has very little to do with SQL Injection. You are talking about user permissions. Setting user permissions would have zero effect on protecting you from SQL Injections if you don't sanitize your user input and don't use prepared statements with PDO.
Read more about SQL Injections: SQL Injections and PDO
SQL 注入和转义对很多人来说听起来很神奇,就像抵御某些神秘危险的盾牌,但是:不要害怕它 - 这没什么神奇的。这只是让查询能够处理特殊字符的方法。
所以,不要发明新的魔法护盾以及如何保护魔法注入危险的方法! 相反,尝试了解输入的转义是如何工作的。
最好的办法就是看看逃避到底做了什么。假设输入字符串是:
转义之后:
实际上它只转义了单个斜杠。这是您唯一需要确保的事情 - 当您在查询中插入字符串时,语法将是正确的!
这没有什么神奇的,比如危险盾之类的,它只是为了确保结果查询具有正确的语法!(当然,如果不正确,它可以被利用)
查询解析器然后查看\' 序列并知道它仍然是变量,而不是其值的结尾。它将删除反斜杠,并且以下内容将存储在数据库中:
这与用户输入的值完全相同。这正是您想要在数据库中拥有的内容!
因此,这意味着如果您从数据库中获取该字符串并希望在查询中再次使用它,则需要再次对其进行转义以确保生成的查询具有正确的语法。
但是,在您的示例中,需要提及的非常重要的一点是
magic_quotes_gpc
指令!此功能会自动转义所有用户输入(gpc - _GET、_POST 和 _COOKIE)。 这是一个邪恶的功能,专为那些不了解 SQL 注入的人而设计。它是邪恶的,有两个原因。第一个原因是,您必须区分第一个和第二个查询的大小写 - 在第一个查询中您不会转义,而在第二个查询中您会转义。大多数人所做的就是关闭“功能”(我更喜欢这个解决方案)或首先取消转义用户输入,然后在需要时再次转义。 unescape 代码可能如下所示:
第二个原因是因为不存在“通用引用”。
引用时,总是引用某些特定输出的文本,例如:
like
mysql 查询的表达式对于每种情况,您需要不同的引用,因为每种用法都存在于不同的语法上下文中。这也意味着不应在 PHP 的输入处进行引用,而应在特定的输出处进行引用!这就是像
magic_quotes_gpc
这样的功能被破坏的原因(永远不要忘记处理它,或者更好,确保它被关闭!!!)。那么,在这些特殊情况下,人们会使用什么方法来引用呢? (请随意纠正我,可能有更现代的方法,但这些对我有用)
mysql_real_escape_string($str)
mysql_real_escape_string(addcslashes($str, "%_"))< /code>
htmlspecialchars($str)
json_encode()
- 仅适用于 utf8!我将我的函数用于 iso-8859-2mysql_real_escape_string(addcslashes($str, '^.[]$()|*+?{}'))
- 在这种情况下你不能使用 preg_quote 因为反斜杠将被转义两次!preg_quote()
SQL injection and escaping sound magical to many people, something like shield against some mysterious danger, but: don't be scared of it - it is nothing magical. It is just the way to enable special characters being processed by the query.
So, don't invent new magial shields and ways how to protect the magical injection danger! Instead, try to understand how escaping of the input works.
The best would be just to have a look what escaping really does. Say the input string is:
after escaping:
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!
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:
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:
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:
like
expression for mysql queryFor 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)
mysql_real_escape_string($str)
mysql_real_escape_string(addcslashes($str, "%_"))
htmlspecialchars($str)
json_encode()
- only for utf8! I use my function for iso-8859-2mysql_real_escape_string(addcslashes($str, '^.[]$()|*+?{}'))
- you cannot use preg_quote in this case because backslash would be escaped two times!preg_quote()