我一直在互联网上搜索一种在JavaScript中定义查询的方法,将该查询传递给PHP。让PHP建立一个MySQL连接,执行查询并返回json编码的结果。
然而,我担心这种方法的安全性,因为用户可能会篡改查询并执行您不希望他们执行的操作或请求您不希望他们看到的数据。
在像这样的应用程序/插件中,您建议使用哪种安全措施来阻止用户请求我不想要的信息?
我的插件的最终结果将类似于
var data = Querier({
table: "mytable",
columns: {"column1", "column2", "column3"},
where: "column2='blablabla'",
limit: "10"
});
我将让该函数发出一个AJAX请求,并使用上述数据在PHP中执行查询。我想知道这会带来什么样的安全风险以及如何预防它们。
答案 0 :(得分:4)
从您的问题中不清楚您是否允许用户键入将针对您的数据库运行的查询,或者您在浏览器中运行的代码是否正在执行此操作(例如,不是用户)。
如果是用户:您必须 真正信任他们 ,因为他们可以(并且可能会)销毁您的数据库。< / p>
如果您的代码在浏览器中运行并且正在创建它们: 不要这样做。 相反,请拥有客户端 - 侧码将数据发送到服务器,并使用完整的预防措施在服务器上制定查询,以防止SQL注入(参数化查询等)。
重新更新:
我至少可以看到几个问题:
这里存在风险:
where: "column2='blablabla'"
现在,假设我决定在将其发送到服务器并将其更改为:
之前先了解它。where: "column2=');DROP TABLE Stuff; --"
您无法向服务器发送完整的WHERE
子句,因为您无法信任它。这是参数化查询的重点:
相反,请按名称指定列,并在PHP端,确保您正确处理参数值(more here)。
var data = Querier({
table: "mytable",
columns: {"column1", "column2", "column3"},
where: {
column2: {
op: '=',
value: 'blablabla'
}
}
limit: "10"
});
现在,您可以在不盲目信任客户端文本的情况下构建查询;您需要对列名称,运算符等进行彻底验证。
向全世界公开有关您的计划的信息是免费放弃信息。安全是一个洋葱,洋葱的外层之一是默默无闻。它本身并不足够,但它是一个起点。因此,不要让您的客户端代码(因此读取它的任何人)知道您的表名和列名是什么。考虑使用服务器端名称映射等
答案 1 :(得分:3)
根据您打算如何做,您可能会有一个比这个经济体更大的洞或者根本没有洞。
如果您打算在客户端上编写查询,并发送到php,我会创建一个只有select
,insert
,{{1}的用户}和delete
,没有访问任何其他数据库的权限
如果您使用SQlite,请忽略此项
我建议反对这个!
如果您在服务器端上构建查询,只需向服务器提供您想要的数据!
我会将代码更改为:
update
在服务器端,将生成查询:
var link = QuerierLink('sql.php');//filename to use for the query
var data = Querier('users',link);//locks access to only this table
data.select({
columns: ['id','name','email'],
where: [
{id:{'>':5}},
{name:{'like':'%david%'}}
],
limit:10
});
使用起来要好得多。
使用预先准备的语句,您可以使用:
select `id`,`name`,`email` from `db.users` where `id`>5 and `name` like '%david%' limit 10
传递给PDO,伪代码:
select `id`,`name`,`email` from `db.users` where `id`>:id and `name` like :name limit 10
这是首选方式,因为您可以更好地控制传递的内容。
此外,在表名称中设置完全数据库名称,以避免用户访问其他表/数据库中的内容。
其他数据库包括$query='select `id`,`name`,`email` from `'.$database_name.'.users` where `id`>:id and `name` like :name limit 10';
$result=$PDO->exec($query,array(
'id'=>5,
'name'=>'%david%'
)
);
,其中包含来自整个数据库的每一条信息,包括用户列表和限制。
忽略这个为SQlite。
如果您要使用MySQL / MariaDB / other,则应禁用所有读/写权限。
你真的不希望任何人将文件写入你的服务器!特别是他们希望的任何位置
风险:他们有一只新的小狗让袭击者做他们想做的事!这是一个大量的洞
解决方案:使用FILE privileges或系统变量argument --secure_file_priv
禁用@@secure_file_priv
或限制使用information_schema
阻止外部访问的目录的访问权限。
如果您使用SQlite,只需为每个连接的客户端创建一个基于模板文件的.htaccess
文件。然后,当用户关闭连接时删除该文件,或者每隔 n 分钟删除 x time 之前的文件。
风险:用.sqlite(3)
个文件填充磁盘
解决方案:尽快清除文件或使用带.sqlite
作业的ramdisk。
我很久以前想要实现这样的东西,这是锻炼我心灵的好方法。
也许我会像这样实现它!
答案 2 :(得分:0)
更重要的是要注意您为此类操作授予MySQL用户的权限。
例如,您不希望它们DROP数据库,也不希望执行此类请求:
LOAD DATA LOCAL INFILE '/etc/passwd' INTO TABLE test FIELDS TERMINATED BY '\n';
您必须限制对此MySQL用户启用的操作以及他访问过的表。
访问总数据库:
grant select on database_name.*
to 'user_name'@'localhost' identified by 'password';
访问表格:
grant select on database_name.table_name
to 'user_name'@'localhost' identified by 'password';
然后......还有什么...这应该避免不必要的SQL注入更新/修改表或访问其他表/数据库,至少,只要SELECT到特定的表/数据库是你授予的唯一权限这个用户。
但是它不会避免用户发起可能需要你所有CPU的愚蠢的糟糕性能请求。
var data = Querier({
table: "mytable, mytable9, mytable11, mytable12",
columns: {"mytable.column1", "count(distinct mytable11.column2)",
"SUM(mytable9.column3)"},
where: "column8 IN(SELECT column7 FROM mytable2
WHERE column4 IN(SELECT column5 FROM mytable3)) ",
limit: "500000"
});
如果您不希望MySQL服务器可能关闭,您必须检查传递的数据。
答案 3 :(得分:0)
简介JavaScript数据访问简介
因此,您希望快速构建一个非常酷的Web 2.0 JavaScript应用程序,但是您不想花费所有时间编写接线代码来访问数据库吗?传统上,要从数据库到前端一直获取数据,您需要使用所有创建,读取,更新和删除(CRUD)方法为数据库中的每个表编写一个类。然后,您需要在其上放置一些编组代码,以便为前端提供访问层。然后将JavaScript库放在其上以访问后端。太痛苦了!
This文章介绍了一种替代方法,您可以使用单个数据库类来包装多个数据库表。单个驱动程序脚本将前端连接到后端,前端的另一个包装类使您可以访问所需的所有表。
// Sample functions to update authors
function updateAuthorsTable() {
dbw.getAll( function(data) {
$('#authors').html('<table id="authors"><tr><td>ID</td><td>Author</td></tr></table>');
$(data).each( function( ind, author ) {
$('#authors tr:last').after('<tr><td>'+author.id+'</td><td>'+author.name+'</td></tr>');
});
});
}
$(document).ready(function() {
dbw = new DbWrapper();
dbw.table = 'authors';
updateAuthorsTable();
$('#addbutton').click( function() {
dbw.insertObject( { name: $('#authorname').val() },
function(data) {
updateAuthorsTable();
});
});
});
我认为这正是您正在寻找的。这样你就不必自己构建它。