【发布时间】:2011-11-09 15:15:21
【问题描述】:
在标准 Ajax 中,where 和 order by SQL 子句由程序(而非用户)提供,例如
var url = ".select?dd=emp&where="+escape("emp_tp='abc' and hire_dt<current_date-'2 years' and super_emp_id is distinct from emp_id")
在服务器上回答
$where = (isset($_GET['where'])) ? pureClause($_GET['where']) : null;
$order = (isset($_GET['order'])) ? pureClause($_GET['order']) : null;
...
$query = $query.(($where)?" where $where":'').(($order)?" order by $order":'');
问题是pureClause 函数应该是什么样子?
现在pureClause 如果存在以下任何一种情况,就会引发错误:
; select insert update delete drop create truncate
如果其他注入导致查询失败,没关系,只要数据完好。
对我来说这似乎足够了,但在我心里,我知道我错了。
说明:
- 在 Postgres 中准备好的语句虽然非常快,但设置和维护起来很麻烦 - 它们适用于使用良好的查询,但不适用于自定义查询。
- 为每个事务创建一个准备好的语句是一个 巨大的 db 命中。如果可以在应用级别获得安全性,则更可取。
最后,考虑 where 子句
emp_tp='abc' and hire_dt=current_dt-'2 years' and super_emp_id is distinct from emp_id
这里有多少占位符?这需要在被输入带有占位符的准备好的语句之前正确解析,对吗?还是我完全错过了这条船?
主要事实:
- 不为参数化的预处理语句编写 SQL 子句解析器并不实际
- 不编写保证无害的 SQL 子句清理程序并不实际
解决方案:
对于 SELECTS,随机 SQL 可能是个问题:既然保护数据库太难了,那就让数据库保护自己吧!有不同的用户有不同的角色/权限。使用只读用户进行选择。对于普通 SQL,这保证了这些语句不会产生 DML。
最佳实践:四个 db 用户访问
-
developer,做所有事情(从不在网络应用中用作连接) -
dml- 几乎可以在所有东西上选择 / dml(必须用于 dml) -
read- 可以选择(用于所有选择,无论是准备好的还是文本) -
login- 只能执行登录/密码功能(在登录过程中使用)
密码保护:
-
dml和read可能无法通过 select 或 dml 访问密码数据 -
login应仅通过受保护的函数访问密码数据,例如,
- 只有
login可以运行login()和set_password()函数 - 根据您的数据库,
login可能需要 sql 访问密码列 - 根据您的数据库,
password列可能会受到保护;如果没有,那么应该从user表中移出到它自己的安全表中
使用管理员工具在mysql 中进行设置大约需要 30 分钟,其中包括编写登录功能和拆分密码列的时间。
【问题讨论】:
-
使用占位符。动态生成的查询不会改变这一点。我发现这种方法比
foo_real_escape_string的(应该)过时的方法不太理想。如果我想要寻找“drop”怎么办? -
@pst - 1) 占位符不暗示准备好的语句吗? 2) 如果 where 子句类似于 "emp_tp='abc' and hide_dt>current_date-'2 years' and super_emp_id!=emp_id" 将需要解析子句并为每个部分创建一个占位符并提取常量与列名等- 我错过了什么吗?
-
啊。一个智能问题的美丽示例,其中“使用准备好的陈述”模因不是答案。可悲的是,它可能仍将最终获得最高投票的贡献。密切相关:Escaping field names in PDO statements
-
@Pekka 我不建议使用字段名称作为准备好的语句参数。您链接到的question 有一个非常特殊的要求,其中字段名称是用户输入的一部分。在这里,我只是将传入的字段名称参数映射到实际的表字段名称,并将传入的输入放入准备好的语句参数中。
-
准备好的语句工作量太大,所以列名是一个附带问题。核心问题是,我们至少可以做些什么来确保一个有效的语句,不确定 where 和子句,不执行 dml?因此,我对 raise exception if 子句的想法有一个 dml 动词。
标签: javascript sql security sql-injection