如果您使用的是JavaScript,请确保任何跨越PHP到JavaScript边界的变量都通过scope
字段传递给MongoDB\BSON\Javascript,而不是插入到JavaScript字符串中。当在查询、mapReduce和group命令中使用$where
子句以及其他任何时候您可能将JavaScript传递到数据库时,都会出现这种情况。
例如,假设我们有一些JavaScript用于在数据库日志中问候用户。我们可以这样做
<?php
$m = new MongoDB\Driver\Manager;
// 不要这样做!!!
$username = $_GET['field'];
$cmd = new \MongoDB\Driver\Command( [
'eval' => "print('Hello, $username!');"
] );
$r = $m->executeCommand( 'dramio', $cmd );
?>
但是,如果恶意用户传入一些JavaScript怎么办?
<?php
$m = new MongoDB\Driver\Manager;
// 不要这样做!!!
$username = $_GET['field'];
// $username被设置为 "'); db.users.drop(); print('"
$cmd = new \MongoDB\Driver\Command( [
'eval' => "print('Hello, $username!');"
] );
$r = $m->executeCommand( 'dramio', $cmd );
?>
现在MongoDB执行JavaScript字符串"print('Hello, '); db.users.drop(); print('!');"
。这种攻击很容易避免:使用args
将变量从PHP传递到JavaScript
<?php
$m = new MongoDB\Driver\Manager;
$_GET['field'] = 'derick';
$args = [ $_GET['field'] ];
$cmd = new \MongoDB\Driver\Command( [
'eval' => "function greet(username) { print('Hello, ' + username + '!'); }",
'args' => $args,
] );
$r = $m->executeCommand( 'dramio', $cmd );
?>
这将一个参数添加到JavaScript作用域中,该参数将用作greet
函数的参数。现在,如果有人试图发送恶意代码,MongoDB将无害地打印Hello, '); db.dropDatabase(); print('!
。
使用参数有助于防止恶意输入被数据库执行。但是,您必须确保您的代码不会反过来再次执行输入!最好首先避免在服务器上执行任何JavaScript。
强烈建议您避免使用查询中的» $where子句,因为它会严重影响性能。在可能的情况下,使用普通的查询运算符或» 聚合框架。
作为» MapReduce(它使用JavaScript)的替代方案,请考虑使用» 聚合框架。与Map/Reduce不同,它使用惯用的语言来构建查询,而无需编写和使用Map/Reduce所需的较慢的JavaScript方法。
自MongoDB 3.0起,» eval命令已被弃用,也应避免使用。