在标准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
如果其他注入导致查询失败,那很好,只要数据完好无损。
对我来说,这似乎已经足够了,但在我心里,我知道我错了。澄清:
最后,考虑where子句
emp_tp='abc' and hire_dt=current_dt-'2 years' and super_emp_id is distinct from emp_id
这里有多少占位符?这需要在被放入带有占位符的预准备语句之前正确解析,对吧?还是我完全错过了船?
主要事实:
解决方案:
对于SELECTS,随机SQL可能是一个问题:因为保护数据库太难了,让数据库保护自己!让不同的用户拥有不同的角色/权限。使用只读用户进行选择。对于普通的SQL,这可以保证这些语句不会出现DML。
最佳做法:四个数据库用户访问
developer
,尽一切努力(永远不会在网络应用中用作连接)dml
- 可以在几乎所有内容上选择/ dml(必须用于dml)read
- 可以选择(用于所有选择,无论是准备还是文本)login
- 只能执行登录/密码功能(在登录过程中使用)密码保护:
dml
和read
可能无法通过select或dml访问密码数据login
应仅通过受保护的功能访问 密码数据,例如function login( username, password ) - returns user_id function set_password( usr_id, password ) - sets password
login
可以运行login()
和set_password()
函数login
可能需要sql访问密码列password
列可能会受到保护;如果没有,那么应该从user
表移出到自己的安全表使用管理员工具在mysql
中进行此设置大约需要30分钟,包括编写登录功能和拆分密码列的时间。
答案 0 :(得分:5)
您正在做的是sql注入的定义,无法清理。您无法以安全的方式传递WHERE
条款期末故事。您必须在服务器端构建此部分查询。您没有意识到这一点的事实意味着您必须阅读有关sql注入的更多信息,显然要求StackOverflow是解决此问题的不安全方法。担心的是,您可能永远无法了解此漏洞的基本原理。
$order
可以通过白名单以安全的方式完成。例如:
if(in_array($_GET['order'],$list_of_rows)){
$order=$_GET['order'];
}
如果您传入的是表名或列名,请确保根据白名单进行检查,否则这将是sql注入。
答案 1 :(得分:1)
始终使用准备好的陈述。它将处理输入转义并避免sql注入。不需要pureClause
这样的黑客攻击。
查看mysqli_stmt::prepare()
答案 2 :(得分:1)
正如@Stephen建议的那样,提供WHERE作为对象,然后解析对象并生成安全的SQL var where = { emp_tp:{ 条件:平等 价值:'abc' } var order = { emp_tp:'ASC' }
将其发送为json:
var params = {
w: where,
o: order
}
$.post(url,params,function(result){...}, 'json');
在PHP中
$where = isset($_POST['w']) ? json_decode($_POST['w') : array();
if (!empty($where)) {
foreach ($where as $field => $data) {
// validate that field exists
// validate that operator is valid
$sql .= sprintf('%s %s "%s"', $field, $data->operator, mysql_escape_string($data->value));
}
}
答案 3 :(得分:1)
知道了!通过仅被授予数据库SELECT权限的数据库用户(连接)来路由所有这些查询!
尝试DML会窒息。这不会阻止DoS攻击(有很多方法可以做到这一点!),但确实可以保护数据。安全查询也不会像登录那样。但对于客户端生成的WHERE和ORDER,以防止DML为目标,这应该可以正常工作。
十年/十五年前总是为不同的角色设置不同的用户,但是使用app layer等等已经摆脱了习惯。重新投资这些原则可能是一个好主意。
除非听到不同的意思,否则会将此标记为正确的答案 - 它符合所有标准,但它如何避免了写一个消毒剂在理论上不可能的挑战。