使用JS执行MySQL个查询及其涉及的安全问题

Use JS to execute MySQL queries and the security issues it involves

我一直在互联网上搜索在 JavaScript 中定义查询的方法,然后将该查询传递给 PHP。让PHP建立一个MySQL连接,执行查询并对return结果进行json编码。

但是我担心的是这种方法的安全性,因为用户可能会篡改查询并执行您不希望他们做的事情或请求您不希望他们看到的数据。

问题

在这样的 application/plugin 中,您建议采取什么样的安全措施来防止用户请求我不希望他们请求的信息?

编辑

我的插件的最终结果将类似于

var data = Querier({
    table: "mytable",
    columns: {"column1", "column2", "column3"},
    where: "column2='blablabla'",
    limit: "10"
});

我将让该函数发出 AJAX 请求并使用上述数据在 PHP 中执行查询。我想知道这会引发哪些安全风险以及如何预防这些风险。

从你的问题中不清楚你是否允许 用户 键入将 运行 针对你的数据库的查询,或者你的代码是否 运行浏览器中的 ning 正在执行此操作(例如,不是用户)。

如果是用户:您必须真正信任他们,因为他们可以(并且可能会)破坏您的数据库.

如果是您的代码运行在浏览器中创建它们:不要那样做。 相反,让 client-side 代码将数据发送到服务器,并使用全面的预防措施在服务器上制定查询以防止 SQL 注入(参数化查询等)。


回复您的更新:

我至少可以看到几个问题:

  1. 这里有一个风险:

    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"
    });
    

    现在您无需盲目信任来自客户端的文本即可构建查询;您需要对列名、运算符等进行彻底验证。

  2. 向全世界公开你的计划信息就是免费提供信息。安全是一个洋葱,洋葱的外层之一是默默无闻。它本身远远不够,但它是一个起点。所以不要让您的客户端代码(以及任何阅读它的人)知道您的 table 名称和列名称是什么。考虑使用server-side名称映射等

根据您打算如何做,您可能会遇到比当前经济中出现的漏洞更大的漏洞,或者根本没有漏洞。

如果您要在 客户端 上编写查询并发送到 php,我会创建一个只有 select 的用户, insertdeleteupdate,无权访问任何其他数据库。
如果您使用 SQlite,请忽略此选项。
我反对这样做!

如果您在服务器端构建查询,只需将您想要的数据填充到服务器即可!

我会把代码改成这样:

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

这样用起来会好很多。

对于准备好的语句,您使用:

select `id`,`name`,`email` from `db.users` where `id`>:id and `name` like :name limit 10

传递给PDO,伪代码:

$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%'
    )
);

这是首选方式,因为您可以更好地控制传递的内容。

此外,在 table 的名称中设置 确切的 数据库名称,这样您就可以避免用户访问其他 tables/databases.[=61 的内容=] 其他数据库包括 information_schema,其中包含来自整个数据库的 每条信息 ,包括用户列表和限制。
对于 SQlite,请忽略此选项。


如果您要使用 MySQL/MariaDB/other,您应该 禁用所有 read/write 权限
您真的不希望任何人将文件写入您的服务器!特别是 任何 他们想要的位置。
风险:他们有一只新的小狗供攻击者为所欲为!这是一个洞。
解决方案:禁用FILE privileges or limit the access to a directory where you block external access using .htaccess, using the argument --secure_file_priv or the system variable @@secure_file_priv.

如果您使用 SQlite,只需基于模板文件为每个连接的客户端创建一个 .sqlite(3) 文件。然后,当用户关闭连接时删除文件,或者每 n 分钟删​​除早于 x time.
的文件 风险:用 .sqlite 个文件填满您的磁盘。
解决方案:尽快清除文件或使用带有 cron 作业的 ramdisk。


我很久以前就想实现这样的东西,这是锻炼我头脑的好方法。
也许我会这样实现!

更重要的是要注意您授予MySQL用户进行此类操作的权限。

例如,您不希望他们删除数据库,也不希望他们执行这样的请求:

  LOAD DATA LOCAL INFILE '/etc/passwd' INTO TABLE test FIELDS TERMINATED BY '\n';

您必须限制对此 MySQL 用户以及他访问过的 table 的操作。

访问总数据库:

  grant select on database_name.*
      to 'user_name'@'localhost' identified by 'password';

访问 table:

  grant select on database_name.table_name
      to 'user_name'@'localhost' identified by 'password';

然后...还有什么...这应该避免不必要的 SQL 注入 updating/modifying table 或访问其他 tables/databases,至少,只要因为 SELECT 到特定 table/database 是您授予该用户的唯一权限。

但它不会避免用户发起愚蠢的低性能请求,这可能需要您的所有 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 服务器可能宕机,您必须对传递的数据进行一些检查

Introducing easy JavaScript data access

So you want to rapidly prototype a really cool Web 2.0 JavaScript application, but you don't want to spend all your time writing the wiring code to get to the database? Traditionally, to get data all the way from the database to the front end, you need to write a class for each table in the database with all the create, read, update, and delete (CRUD) methods. Then you need to put some marshalling code atop that to provide an access layer to the front end. Then you put JavaScript libraries on top of that to access the back end. What a pain!

This 文章介绍了另一种方法,您可以在其中使用单个数据库 class 来包装多个数据库表。单个驱动程序脚本将前端连接到后端,前端的另一个包装器 class 使您可以访问所需的所有表。

Example/Usage

// 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();
        });
    });
});

我想这正是您要找的。这样您就不必自己构建它了。