首先反对目前排名较高的
@pansz
及
@vczh
两位对参数化查询的理解
第一,参数化查询是DB本身提供的功能
第二,各种语言的库在实现参数化查询时可以采用以下两种策略,姑且称之为
第三,回答题主的问题,答案是,不能,DB已经把能做的都做到了,一方面,DB已经提供了两种查询方式分别能正确地适用不同场景,但是DB不可能阻止程序层面错误地使用,首先,plain SQL有存在的必要,但是你无法识别程序送过来的plain SQL到底是写死的还是通过拼接来的
结论,防止SQL注入的责任仍然是在程序这边,应该正确地使用DB提供的机制
以下为新增,本来是打算回复 @吴永志的,不过后来觉得修改答案更合适
其实这就是我所想表达的重点,“数据库提供的功能”这种说法可能会引入歧义,在此重新定义一下,所谓的“数据库提供”指的是,数据库服务端(严格来说是具体到SQL分析引擎)接收到的就是“带参数的SQL语句+参数值”二者分离,与之相对的“非数据库提供”指的是,数据库服务端接收到的是一条单独的SQL语句,其中的参数已经被处理成了具体的值,这个过程是由客户端(可能是最终程序,也可能是某些框架,或者数据库驱动)完成的,这二者是有本质区别的,在第一种实现中,SQL语法引擎明确地知道参数的位置是一个整体,不会再对其进行语法及语义处理,而第二种则不然,参数值仍然会被进行语法及语义处理,客户端所做的就是通过验证、转义等方式尽量地避免参数被解析成语义动作,不同于第一种方式,没有从根本上解决 用户的输入可能被作为指令 这一隐患
从题主的评论来看题主应该是清楚这个机制的,那现在我们来再次回答题主的问题,设想一下为了达到这个目标我所能想到的数据库这边可以做哪些尝试(欢迎补充)
1. 废弃plain SQL ,强制使用参数化查询(并且是上述的真•参数化查询)
这其实没有解决任何问题,首先,使用plain SQL的需求是真实存在的,当然我们假设可以通过空的参数列表来变相进行plain SQL的查询,那这和plain SQL又有何区别,其次,参数化查询仍然是由“带参数的SQL”和参数列表两部分组成的,无法识别和避免程序员在第一部分采用拼接
2. 完全抛弃SQL,提供结构化的接口,例如类似select(tableName, fields, condition)这种机制
这会使得接口异常复杂,且不一定应付得了复杂查询,想想LINQ吧
所以结论仍然是,数据库本身在这个问题上已经做到足够好了,前提是使用者正确地使用其提供的功能
第一,参数化查询是DB本身提供的功能
第二,各种语言的库在实现参数化查询时可以采用以下两种策略,姑且称之为
- 真•参数化查询:将带参数的语句及参数分别发送给DB,这种情况能100%防注入,因为对于DB来说,参数的值绝对不会作为语义要素来解析,据我所知JDBC是这种实现方式
- 伪•参数化查询:将拼接以后的plain SQL发给DB,只不过在拼接过程中会进行校验及转义,据我所知PHP的PDO默认是采用这种实现,不过可以通过设置开关切换为真•参数化查询,个人目前无法理解为什么要放着DB本身提供的正确实现而兜个大圈子,而且这样并不能完全避免风险,因为不能保证目前的校验及转义是否还有没考虑到的情况
第三,回答题主的问题,答案是,不能,DB已经把能做的都做到了,一方面,DB已经提供了两种查询方式分别能正确地适用不同场景,但是DB不可能阻止程序层面错误地使用,首先,plain SQL有存在的必要,但是你无法识别程序送过来的plain SQL到底是写死的还是通过拼接来的
结论,防止SQL注入的责任仍然是在程序这边,应该正确地使用DB提供的机制
以下为新增,本来是打算回复 @吴永志的,不过后来觉得修改答案更合适
其实这就是我所想表达的重点,“数据库提供的功能”这种说法可能会引入歧义,在此重新定义一下,所谓的“数据库提供”指的是,数据库服务端(严格来说是具体到SQL分析引擎)接收到的就是“带参数的SQL语句+参数值”二者分离,与之相对的“非数据库提供”指的是,数据库服务端接收到的是一条单独的SQL语句,其中的参数已经被处理成了具体的值,这个过程是由客户端(可能是最终程序,也可能是某些框架,或者数据库驱动)完成的,这二者是有本质区别的,在第一种实现中,SQL语法引擎明确地知道参数的位置是一个整体,不会再对其进行语法及语义处理,而第二种则不然,参数值仍然会被进行语法及语义处理,客户端所做的就是通过验证、转义等方式尽量地避免参数被解析成语义动作,不同于第一种方式,没有从根本上解决 用户的输入可能被作为指令 这一隐患
从题主的评论来看题主应该是清楚这个机制的,那现在我们来再次回答题主的问题,设想一下为了达到这个目标我所能想到的数据库这边可以做哪些尝试(欢迎补充)
1. 废弃plain SQL ,强制使用参数化查询(并且是上述的真•参数化查询)
这其实没有解决任何问题,首先,使用plain SQL的需求是真实存在的,当然我们假设可以通过空的参数列表来变相进行plain SQL的查询,那这和plain SQL又有何区别,其次,参数化查询仍然是由“带参数的SQL”和参数列表两部分组成的,无法识别和避免程序员在第一部分采用拼接
2. 完全抛弃SQL,提供结构化的接口,例如类似select(tableName, fields, condition)这种机制
这会使得接口异常复杂,且不一定应付得了复杂查询,想想LINQ吧
所以结论仍然是,数据库本身在这个问题上已经做到足够好了,前提是使用者正确地使用其提供的功能