INSERT INTO SELECT对SQL注入有漏洞吗?

huangapple go评论75阅读模式
英文:

Is INSERT INTO SELECT vulnerable to SQL injections?

问题

以下是代码部分的中文翻译:

假设您允许用户将其名称(或任何内容)插入到表中,但某人尝试进行SQL注入,但您正确地使用了预编译语句,因此查询不受影响。

$stmt = $db->prepare("INSERT INTO users (user_name) VALUES (?)");
$stmt->bindParam(1, $_POST['user_name']);

但现在您将插入到user_name列中插入的值插入到另一个表中。

$stmt = $db->prepare("INSERT INTO different_table (name) VALUES (
    SELECT user_name FROM users WHERE userId = ?
)");

user_name是否会被视为字符串(假设为varchar数据类型)?换句话说,您仅在首次插入时需要准备用户输入,并且来自客户端?

编辑

如果user_name列中的值包含注入,现在我想将这个值插入到另一个表中,是否需要首先运行select以获取该值,然后在执行插入时使用预编译语句?像这样?

$stmt = $db->prepare("SELECT user_name FROM users WHERE user_id = 1");

然后

$stmt = $db->prepare("INSERT INTO another_table (name) VALUES (?)");
$stmt->bindParam(1, $resultFromFirstQuery['user_name']);

还是我可以直接像这样做?

$stmt = $db->prepare("INSERT INTO different_table (name) SELECT user_name FROM users WHERE userId = ?");
英文:

Say you let users insert their names (or anything into a table) and someone tries a SQL injection but you properly use prepared statements so the query is not affected.

$stmt = $db->prepare("INSERT INTO users (user_name) VALUES (?)");
$stmt->bindParam(1, $_POST['user_name']);

But now you use that value that was inserted in the user_name column and insert it into another table.

$stmt = $db->prepare("INSERT INTO different_table (name) VALUES (
    SELECT user_name FROM users WHERE userId = ?
)");

Does user_name get treated as a string (assuming a varchar datatype) ? In other words, do you only need to prepare the user input when it first gets inserted and comes from the client ?

Edit

If the value inside user_name contains an injection, and now I want to insert this value in another table do I need to first run a select in order to get the value and then use it in a prepared statement when I do the insert ? Like so ?

$stmt = $db->prepare("SELECT user_name FROM users WHERE user_id = 1");

Then

$stmt = $db->prepare("INSERT INTO another_table (name) VALUES (?)");
$stmt->bindParam(1, $resultFromFirstQuery['user_name']);

Or can I just do something like this ?

$stmt = $db->prepare("INSERT INTO different_table (name) SELECT user_name FROM users WHERE userId = ?");

答案1

得分: 2

我要声明,没有可能发生SQL注入,因为没有构造任何SQL语句。换句话说,SQL注入只能发生在创建SQL语句的编程语言中,而不能发生在SQL语句本身中。

为了详细说明:SQL注入攻击的核心是未经检查的用户输入被用于生成一个SQL语句,该语句超出了用户输入的原始目的。例如,如果您的程序执行以下操作:

$sql = "SELECT * FROM Users WHERE Email = '{input.email}'"

并且用户输入

hacker@example.com' OR 1 = 1; --

作为 {input.email},那么变量 $sql 最终会变成:

SELECT * FROM Users WHERE Email = 'hacker@example.com' OR 1 = 1; --

现在的安全风险来自于在数据库上执行这个未经检查的语句。

在您的示例中,没有构造任何SQL语句。如果执行以下语句:

INSERT INTO table1 SELECT * FROM table2

在查询字符串中没有地方附加未经检查的用户输入。SELECT 的结果可能包含在SQL语境下不安全的输入,但文本字段的值永远不会作为数据库上的语句运行,因此无论您的表中包含 12345 还是 hacker@example.com' OR 1 = 1; -- 都无关紧要。

我能想象的唯一可能情况是,如果您的数据库服务器存在缺陷,并且在特定位置的内存中具有某些特定字节可能导致内存溢出,从而打开了一种攻击途径。但这超出了您的控制范围,这是数据库供应商应该很快修复的问题;这也与SQL注入无关,您无法对此采取任何措施。

英文:

I would claim that no SQL injection is possible because no SQL statement is getting constructed. In other words:, SQL injection can only happen in the programming language creating the SQL statement, not in the SQL statement itself.

To elaborate: the core of a SQL injection attack is that unchecked user input is used to generate a SQL statement which goes beyond the original purpose of the user input. For example, if your program does this

$sql = "SELECT * FROM Users WHERE Email = '{input.email}'"

and a user inputs

hacker@example.com' OR 1 = 1; --

for {input.email}, then the variable $sql ends up being

SELECT * FROM Users WHERE Email = 'hacker@example.com' OR 1 = 1; -- '

The security risk now comes from executing this unchecked statement on your database.

In your example no SQL is being constructed. If you execute the statement

INSERT INTO table1 SELECT * FROM table2

there is no point where unchecked user input is being appended to the query string. The result of the SELECT may contain input that would be unsafe when considered as SQL, but the values of a text field are never run as statements on the database so whether your table contains 12345 or hacker@example.com' OR 1 = 1; -- is not relevant.

The only conceivable case I could think of would be if your database server had a bug, and having some specific set of bytes in memory at a specific location could cause a memory overflow which then opens up an attack vector. But this is outside of your control and something that a database vendor would presumably fix very quickly; it is also something you can do nothing against and has nothing to do with SQL injection.

huangapple
  • 本文由 发表于 2023年4月4日 18:16:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/75928164.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定