白名单用户输入而不是使用预准备语句来阻止sql注入?

时间:2015-04-07 14:45:56

标签: sql sql-injection

我读过几篇关于sql注入预防的文章。他们中的大多数建议使用预准备语句来防止sql注入和白名单只是一个额外的解决方案。我无法得到他们的观点。

恕我直言,白名单用户输入要好得多,因为它还可以防止XSS攻击。没有字符限制时,白名单是不可能的。这种情况很少发生。

让我们在nodejs中考虑这个例子。

准备好的声明

DB.query("UPDATE user SET username=?",username,cb);

白名单

//assume that username is alphabetic
if(!/^[a-z]+$/.test(username)){
    throw new Error('Invalid user name');
}
DB.query("UPDATE user SET username='"+username+"'",cb);

你们觉得怎么样?白名单或准备好的陈述?为什么不建议在准备好的语句上将用户输入列入白名单?

1 个答案:

答案 0 :(得分:5)

准备好的语句绝对可以防止使用它们的语句中的SQL注入漏洞,句点,段落。

验证或"消毒"您的意见可能看起来同样有效,但专家们毫无疑问的共识是,对于准备好的陈述,没有有效的替代方案,并且连接的查询是不可接受的。

在您的服务器被利用之前,有一些方法可以将错误的数据传递给您尚未想象的验证尝试,并且可能永远不会。例如,有一些涉及备用字符集的漏洞利用程序可以直接通过正确的验证或转义。

但除了显而易见的有效性之外,还有一个最重要的原则:你似乎没有考虑的预备陈述的基本和重要方面是它们在"代码和#之间强加了正确的分离34;和"数据。" (在其他环境中,违反代码和数据之间的边界是"缓冲区溢出"漏洞的核心。)在SQL中,查询是代码,提供的值是数据。它们是不同类型的东西,"作为一个原则问题,应该保持隔离状态。

准备好的声明并不是简单地用?替换值。查询和值分别以不同的数据结构提供给数据库服务器。使用这种机制,数据库服务器错误地模糊边界变得字面上不可能

这一事实的有效说明是,您不能将?占位符用于数据库对象标识符,例如表名或列名,并将值作为参数提供。这不起作用,因为它不应该起作用。表名和列名是代码的一部分,而不是数据的一部分。

"不可能"弄错了这个术语,你不能适用于你的输入验证尝试。

用户名也是一个过于简单的例子,因为它们很容易被限制为ascii alpha。许多或大多数其他专栏都没有。稍后进行更改,并且" oops,"你忘了处理某件事。也许这是不可思议的遥远和不可能的事情,但现在它只是等待被剥削。

您的问题也有很多优秀的评论,您可以考虑这些评论。

准备好的陈述是将外部数据传递到数据库的正确机制......但我认为专家和专业人员甚至不会问自己数据来源是否值得信赖 - 我们使用占位符并准备好一致且无条件地陈述,而不考虑我们通过的数据的来源。

当然,显而易见的是,我的观点是不要轻视防范其他漏洞,但这不是准备好的声明的作用。然而,在协助任务时可能会出现有效的其他机制,无论它们是否有用于它们的预期目的,它们都不能代替在通往dbms的途中正确处理数据。