我读过几篇关于sql注入预防的文章.他们中的大多数建议使用预准备语句来防止sql注入和白名单只是一个额外的解决方案.我无法得到他们的观点.
恕我直言,白名单用户输入要好得多,因为它还可以防止XSS攻击.没有字符限制时,白名单是不可能的.这种情况很少发生.
让我们在nodejs中考虑这个例子.
DB.query("UPDATE user SET username=?",username,cb);
Run Code Online (Sandbox Code Playgroud)
//assume that username is alphabetic
if(!/^[a-z]+$/.test(username)){
throw new Error('Invalid user name');
}
DB.query("UPDATE user SET username='"+username+"'",cb);
Run Code Online (Sandbox Code Playgroud)
你们有什么感想?白名单或准备好的陈述?为什么不建议在准备好的语句上将用户输入列入白名单?
准备好的语句绝对可以防止使用它们的语句中的SQL注入漏洞,句点,段落.
验证或"消毒"您的意见可能看起来同样有效,但专家们毫无疑问的共识是,准备好的陈述没有有效的替代方案,连接的查询是完全不可接受的.
在您的服务器被利用之前,有一些方法可以获得您尚未想象的错误数据以及可能永远不会想到的错误数据.例如,有一些涉及备用字符集的漏洞利用程序可以直接通过正确的验证或转义.
但除了明显的有效性之外,还有一个最重要的原则:你似乎没有考虑的预备陈述的基本和重要方面是它们在"代码"和"数据"之间强加了正确的分离.(在其他环境中,违反代码和数据之间的边界是"缓冲区溢出"漏洞的核心.)在SQL中,查询是代码,提供的值是数据.它们是不同类型的"事物",应该保持隔离,这是一个原则问题.
准备好的语句不会简单地?用值替换.查询和值分别以不同的数据结构提供给数据库服务器.使用这种机制,数据库服务器实际上不可能弄错并模糊边界.
这一事实的有效说明是,您不能将?占位符用于数据库对象标识符,如表名或列名,将值作为参数提供.这不起作用,因为它不应该工作.表名和列名是代码的一部分,而不是数据的一部分.
错误的"不可能"是一个你无法应用于输入验证尝试的术语.
用户名也是一个过于简单的例子,因为它们很容易被限制为ascii alpha.许多或大多数其他专栏都没有.稍后做出改变,然后"哎呀",你忘了处理某些事情.也许这是不可思议的遥远和不可能的事情,但现在它只是等待被剥削.
您的问题也有一些很好的评论,您可以考虑这些评论.
准备好的陈述是将外部数据传递到数据库的正确机制......但我认为专家和专业人员甚至不会问自己数据来源是否值得信赖 - 我们始终如一地无条件地使用占位符和准备好的陈述,不考虑我们传递的数据的来源.
当然,显而易见的是,我的观点不是淡化防范其他漏洞,但这不是准备好的声明的作用.然而,在协助任务时可能会出现有效的其他机制,无论它们是否有用,它们都可能用于预期目的,它们不能代替在通往dbms的过程中正确处理数据.