mongodb数组查询

  • 插入测试数据
1
2
3
>db.food.insert({"_id":1, "fruit":["apple","banana","peach"]})
>db.food.insert({"_id":2, "fruit":["apple","kumquat","orange"]})
>db.food.insert({"_id":3, "fruit":["cherry","banana","apple"]})
  • $all(数组元素必须包含)
1
>db.food.find({"fruit":{$all:["apple", "banana"]}}) // 返回_id 为1,3的记录
  • $in (数组元素为其中任意一个)
1
>db.food.find({"fruit":{$in:["apple,", "banana"]}}) // 1,2,3

单个$in 可以省略$in操作符 一下两条查询结果相同

1
2
>db.food.find({"fruit":"apple"}); //1, 2,3
>db.food.find({"fruit":{$in:["apple"]}});//1,2,3

  • $size (数组长度)
    1
    >db.food.find({"fruit":{$size:3}}) // 1, 2,3

也可是使用 $where 来代替

1
>db.food.find({$where:"this.fruit.length == 3"}); // 1, 2, 3

  • $slice(对数组进行分片)

    1
    >db.food.find({}, {"fruit":{$slice:[1,1]}}) //只返回数组第一个元素
  • 查询第一个元素为apple的记录

    1
    2
    >db.food.find({"fruit.0": "apple"});
    >db.food.find({$where:"this.fruit[0] == 'apple'"});

mongodb注入攻击

一直以为注入只存在关系型数据库中,看了这篇文章才知道mongodb也会中招.
翻看php手册发现早就发现有这个问题,以前看手册一直没注意.

数组绑定时的注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
$mongo = new mongoclient();
//选择数据库
$db = $mongo->myinfo;
//选择集合
$coll = $db->test;
$username = $_GET['username'];
$password = $_GET['password'];
$data = array(
'username'=>$username,
'password'=>$password
);
$data = $coll->find($data);
$count = $data->count();
if ($count>0) {
foreach ($data as $user) {
echo 'username:'.$user['username']."</br>";
echo 'password:'.$user['password']."</br>";
}
}
else{
echo '未找到';
}
?>

如果传入url为

1
http://127.0.0.1/2.php?username[$ne]=test&password[$ne]=test

mongodb最终执行:

1
db.test.find({username:{'$ne':'test'},password:{'$ne':'test'}});

php会把test集合内的所有数据全部便利出来。

防止注入的方法也很简单, 注意参数的检验.

1
2
3
4
5
6
7
8
9
<?php
...
$username = $_GET['username'];
$password = $_GET['password'];
$username = is_string($username) ? $username : '';
$password = is_string($password) ? $password : '';
...
?>

接受参数拼接直接以命令行执行的注入可以参考php手册 使用MongoCode 进行转椅后再使用.

检查文档是否存在

<?php
    $mongo = new MongoClient();
    $db = $mongo->dbName;
    $collection = $db->collectionName;

    $cursor = $collection->find(
        $criteria, 
        array('_id' => 1)
    )->limit(1);

    if($coursor->count() == 0){
      exit('not exist');
    }

    exit('exits');