在 javascript 中公开 MySQL 表名称是不是存在安全风险?

Posted

技术标签:

【中文标题】在 javascript 中公开 MySQL 表名称是不是存在安全风险?【英文标题】:Is there a security risk in exposing MySQL tables names in javascript?在 javascript 中公开 MySQL 表名称是否存在安全风险? 【发布时间】:2011-07-30 10:20:49 【问题描述】:

我有一个基本上像这样工作的 ajax 方法

function getRow(tableName, idName, idValue, callback)

这样做的明显好处是我有一个函数可以从任何表中检索数据。但是,从安全角度来看,这只是感觉错误,这样做是否存在安全风险?实际读取/操作数据库的相应 php 文件通过先前的身份验证过程得到保护,因此理论上,表名在真空中的可见性不应该是一个风险(更不用说数据库只接受 localhost 连接),但是我想知道是否没有更好/更漂亮的方法来实现这一点。

编辑:只是为了澄清身份验证过程,用户/角色安全性会阻止访问所有表,但用户明确允许的表除外。

【问题讨论】:

如果我用syscolumns作为参数调用这个函数呢? 【参考方案1】:

如果您确定没有 SQL 注入漏洞,并且永远不会,那很好。

如果您确实存在 SQL 注入漏洞,它会使攻击者的工作更加轻松。

不用说(我希望),服务器端脚本必须使用可以通过这种方法公开的表和列的白名单。

【讨论】:

我喜欢这样,稍微容易一些,因为如果你有 SQL 注入漏洞,那么查找表名很容易。 @mcdonald:如果你无法从漏洞中获得任何输出,它会变得容易一些。 +1,我同意@SLaks。但是(只是一个想法),我认为知道表的名称只会让他们更容易一点。我通常做的,只是因为我不喜欢人们知道我在后台拥有的任何东西(即表、数据库、文件等),我通常会异或我的表和文件名的名称。这并不意味着“阻止”或“阻止”人们弄清楚它,但它确实让普通人更难弄清楚正在使用的名字。但是,您可能不希望必须对名称进行 XOR 处理所带来的额外开销。 @JTS:如果你这样做,你还不如在服务器上使用从表名到随机字符串的硬编码查找,这样客户端就永远看不到任何真实姓名。跨度> 【参考方案2】:

单独的表名称并没有那么糟糕,但是,您似乎正在制作的 API 可能不是最好的主意...

仔细考虑是否存在人们不应该查询的表,因为从外观上看,我可以从客户端查询数据库中的任何表。例如:

getRow('users', 'id', '7', function(data)console.log(data))

如果用户表返回他们的密码怎么办?即使它被散列,那也不好。还是他们的电子邮件?如果我想收集所有用户的电子邮件怎么办?我可以编写非常简单的脚本来做到这一点。

【讨论】:

希望这就是他所说的服务器端身份验证。 没错,希望身份验证不会停留在“可以执行查询!”【参考方案3】:

这是一种风险,因为它会向攻击者提供信息。这与提供您正在使用的软件的软件版本相同。它本身不是漏洞,但它是漏洞之门。

【讨论】:

【参考方案4】:

这是一个非常糟糕的主意

例如,假设您正在使用此代码:

$table_name=mysql_real_escape_string($_GET['table']);
$id_name=mysql_real_escape_string($_GET['idname']);
$id_value=mysql_real_escape_string($_GET['idvalue']);

mysql_query("select * from `$table_name` where `$id_name`='$id_value'");

这可以通过多种方式加以利用:

不是 SQL 注入

这个查询会返回mysql.user中的root用户,这个是

?table=mysql.user&idname=user&idvalue=root 此请求将创建查询:

select * frommysql.userwhereuser='root'

SQL 注入:

这是因为mysql_real_escpae_string 不会转义反引号:``

?table=`table where 1 union select * from mysql.user/*&idname=junk&idvalue=junk

【讨论】:

是的,但是如果我没记错的话,MySQL 表名只能包含\w 字符。但是应该验证输入。 @webarto 不公开这样的功能只是愚蠢的。您可以在不需要句点的情况下获取同一数据库上另一个用户的密码哈希。【参考方案5】:

您可以在 JS 中显示例如 users 表名,但在服务器端添加像 forum_users 这样的前缀,这将是数据库中的实际表名。这样如果有人找到注入点,他会尝试DROP TABLE users,如果幸运的话,查询将失败:)

还为表和列添加白/黑列表,添加 LIMIT 1(不要循环),不要返回多个数组,并且应该使用类似这样的东西进行清理。

$select = preg_replace("#[\w]#", "", $_GET["select"]);
$from = preg_replace("#[\w]#", "", $_GET["from"]);
$where = preg_replace("#[\w]#", "", $_GET["where"]);
$equals = mysql_real_escape_string($_GET["equals"]);

$query = "SELECT $select FROM $from WHERE $where = '$equals' LIMIT 1";

【讨论】:

【参考方案6】:

客户端上的直接数据库 API 当然应该用于非常特殊的情况。但是您可以使用白名单轻松保护它。以 PHP 为例:

if (in_array($tableName, array("users", "log", "messages", ...))) 

所以从安全的角度来看,我认为这没什么大不了的,只要你在这里有一个固定的列表。

【讨论】:

以上是关于在 javascript 中公开 MySQL 表名称是不是存在安全风险?的主要内容,如果未能解决你的问题,请参考以下文章

MySQL数据表的修改:修改表名

查询mysql数据库中所有表名

在 MySQL 中使用 SELECT 语句获取表名

查询mysql数据库中所有表名

如何在 JavaScript 中公开方法

在 Qt 中将 C++ 对象公开给 Javascript