Node.js Mongodb 密码特殊字符 @

在去年的 DB 勒索事件之后, 不少的同学开始加强 Mongodb 的安全性, 其中一种办法就是设置复杂的密码. 那么问题来了, 如果设置的密码里包含一些如 “@”, “:” 一样的特殊字符怎么办?

mongodb://username:password@host:port/db

这种情况可能使得你的 Mongodb 连接串不能被正常解析, 并且完全有可能出现. 烦人的地方在于:

  1. 使用 “” 双引号将 password 包起来没有用
  2. 使用 \@ 转义也没有用

解决方案 1

开启 uri_decode_auth 功能, 拼接连接串之后先 encode 一下, 然后通过 uri_decode_auth 在 driver 内部 decode 来绕过这个问题

mongoClient.connect("mongodb://username:p%40ssword@host:port/dbname", {
    uri_decode_auth: true
    }, function(err, db) {

    }
);

解决方案2

老老实实查文档, 在 options 中指明:

mongoose.connect('mongodb://localhost/test',
                 {user: 'username', pass: 'p@ssword'},
                 callback);

mongodb 通过数组某一元素查询

> db.test.insert({ arr: [ 1, 2, 3, 4, 5] })
WriteResult({ "nInserted" : 1 })

> db.test.insert({ arr: [ 5, 6, 7, 8, 9 ] })
WriteResult({ "nInserted" : 1 })

> db.test.find({ arr : { $in : [ 3 ] } })
{ "_id" : ObjectId("5779d5b99f113cca8e7002c1"), "arr" : [ 1, 2, 3, 4, 5 ] }

> db.test.find({ arr : { $in : [ 5 ] } })
{ "_id" : ObjectId("5779d5b99f113cca8e7002c1"), "arr" : [ 1, 2, 3, 4, 5 ] }
{ "_id" : ObjectId("5779d6879f113cca8e7002c2"), "arr" : [ 5, 6, 7, 8, 9 ] }

> db.test.find({ arr : { $in : [ 3, 4, 5 ] } })
{ "_id" : ObjectId("5779d5b99f113cca8e7002c1"), "arr" : [ 1, 2, 3, 4, 5 ] }
{ "_id" : ObjectId("5779d6879f113cca8e7002c2"), "arr" : [ 5, 6, 7, 8, 9 ] }

> db.test.find({ arr: 5 })
{ "_id" : ObjectId("5779d5b99f113cca8e7002c1"), "arr" : [ 1, 2, 3, 4, 5 ] }
{ "_id" : ObjectId("5779d6879f113cca8e7002c2"), "arr" : [ 5, 6, 7, 8, 9 ] }

Mongodb Error: network error while attempting to run command ‘isMaster’ on host

$ mongo
MongoDB shell version: 3.2.4
connecting to: test
2016-05-16T14:33:58.461+0800 E QUERY    [thread1] Error: network error while attempting to run command 'isMaster' on host '127.0.0.1:27017'  :
connect@src/mongo/shell/mongo.js:224:14
@(connect):1:6

exception: connect failed

搜了一下有说一个解决方案是在启动参数上加个flag

Solution: add the following option to your mongod command
--bind_ip 127.0.0.1 

不过燃冰暖,随后检查了下日志发现其实就是连接数过多,

...
2016-05-16T14:33:28.311+0800 I NETWORK  [initandlisten] connection accepted from 127.0.0.1:50075 #200 (200 connections now open)
2016-05-16T14:33:28.311+0800 I NETWORK  [initandlisten] connection accepted from 127.0.0.1:50074 #201 (201 connections now open)
2016-05-16T14:33:28.311+0800 I NETWORK  [initandlisten] connection accepted from 127.0.0.1:50089 #202 (202 connections now open)
2016-05-16T14:33:28.312+0800 I NETWORK  [initandlisten] connection accepted from 127.0.0.1:50088 #203 (203 connections now open)
2016-05-16T14:33:28.312+0800 I NETWORK  [initandlisten] connection accepted from 127.0.0.1:50087 #204 (204 connections now open)
2016-05-16T14:33:38.360+0800 I NETWORK  [initandlisten] connection accepted from 127.0.0.1:50092 #205 (205 connections now open)
2016-05-16T14:33:38.360+0800 I NETWORK  [initandlisten] connection refused because too many open connections: 204

根据日志里面的 accepted from ip:port ,找到端口,然后 lsof -i tcp:50075 之类的命令找到访问太多的进程,问题基本上就找到了。

实际上的问题应该是 “connection refused because too many open connections: 204”

node.js Mongodb parseError occured 导致连接断开

情况:node.js 使用原生 mongodb 依赖查询。

最近日志收到如下报错:

[2015-12-28 21:00:01.848] [ERROR] console - [Error: parseError occured]
Error: parseError occured
    at null.<anonymous> (/data/game_server_142/node_modules/mongodb/lib/mongodb/connection/connection_pool.js:198:34)
    at emit (events.js:98:17)
    at Socket.<anonymous> (/data/game_server_142/node_modules/mongodb/lib/mongodb/connection/connection.js:411:20)
    at Socket.emit (events.js:95:17)
    at Socket.<anonymous> (_stream_readable.js:764:14)
    at Socket.emit (events.js:92:17)
    at emitReadable_ (_stream_readable.js:426:10)
    at emitReadable (_stream_readable.js:422:5)
    at readableAddChunk (_stream_readable.js:165:9)
    at Socket.Readable.push (_stream_readable.js:127:10)

查询 mongodb 日志如下:

Mon Dec 28 21:00:00 [conn72] query game_142.player query: { ... 查询 ... } nscanned:101 nreturned:101 reslen:1374301 146ms
Mon Dec 28 21:00:01 [conn72] getmore game_142.player query: { ... 查询 ... } cursorid:5517049421632407939 nreturned:427 reslen:4201834 688ms
Mon Dec 28 21:00:01 [conn71] end connection 10.105.50.74:59131
Mon Dec 28 21:00:01 [conn72] SocketException handling request, closing client connection: 9001 socket exception [2] server [10.105.50.74:59132]
Mon Dec 28 21:00:01 [conn74] end connection 10.105.50.74:59134
Mon Dec 28 21:00:01 [conn70] end connection 10.105.50.74:59130
Mon Dec 28 21:00:01 [conn73] end connection 10.105.50.74:59133

报错之后客户端与mongodb之间的连接断开。

谷歌了不少老外的情况看到 http://stackoverflow.com/questions/19546561/node-mongodb-error-connection-closed-due-to-parseerror 这一篇的情况基本与博主碰到的情况相同。

里面提到 “The production Mongo driver throws away all errors in a catch block.” 然后后面说 node 的原生 npm 模块 mongodb 在它的 1.4 版本里面修复了这个问题。

随后检查了下 node_modules/mongodb/package.json 发现版本确实是新的,不过顺着版本思路检查,发现运维新搭的 mongod server 的版本是 2.0.x 而目前公司服务器用的 mongod 版本是 3.0.3,于是升级 mongod 之后解决了。(真是没有一点点防备啊 (╯‵□′)╯︵┻━┻)

Mongodb 忘记密码

下午刚设置的密码,当时忘记保存,晚上去吃了个晚饭回来就忘记了。研究了一会发现也不难,不过网上没有直接搜到就记录一下。

vim /etc/mongodb.conf          # 修改 mongodb 配置,将 auth = true 注释掉,或者改成 false
service mongodb restart        # 重启 mongodb 服务

mongo                          # 运行客户端(也可以去mongodb安装目录下运行这个)
use admin                      # 切换到系统帐户表
db.system.users.find()         # 查看当前帐户(密码有加密过)
db.system.users.remove({})     # 删除所有帐户
db.addUser('admin','password') # 添加新帐户

vim /etc/mongodb.conf          # 恢复 auth = true
service mongodb restart        # 重启 mongodb 服务