前言

前几天因为使用MongoDB没有设置严格的登陆用户名密码,只设置了固定IP可以访问。结果还是被扫描到了,然后数据就被黑了,都丢了。然后黑客还让我缴纳0.6个比特币……

还好数据有备份,虽然时间早了点儿。。。哎。。。经过这次事件,真的,以后用MongoDB真的要养成设置密码的习惯啊!!!

版本信息

遇到的问题

网站使用Flask开发的,使用Python的时候我习惯配套MongoDB一起使用。我选择的是Flask-Pymongo而不是Flask-MongoEngine。因为因为我开发网站一般都是选择(其实是百分百)前后端分离的方式,前端用Vue,后台接啥都行,然后通过Ajax调用。

而Flask-MongoEngine更像模板渲染的方式的,不符合我的要求,还要定义各种Field,像ORM一样。所以相比之下,我还是感觉Flask-Pymongo更灵活一些。

在MongoDB中,首先要创建一个用户,然后这个用户是在admin数据库中创建的,所以创建好了之后,要先“use admin”,然后进行auth:“db.auth(“your_username”, “your_password”)”。

在pymongo的话,就可以通过下面的方式,先使用client.admin.authenticate进行验证,这个步骤是在admin数据库进行的,然后再连接到别的数据库your_db。

1
2
3
4
client = pymongo.MongoClient()
client.admin.authenticate("your_username", "your_password")
db = client.your_db
coll = db.some_collection

然而在Flask-Pymongo封装后,文档说明如下:

其中没有发现有用于验证的数据库,然后我进行了如下的配置:

1
2
3
4
5
6
7
8
app = Flask(__name__)
app.config['MONGO_DBNAME'] = "your_db"
app.config['MONGO_HOST'] = "localhost"
app.config['MONGO_PORT'] = "27017"
app.config['MONGO_USERNAME'] = "your_username"
app.config['MONGO_PASSWORD'] = "your_password"
mongo = PyMongo(app)

而后出现了“pymongo.errors.OperationFailure: auth failed”的错误

然后这个时候,我把MONGO_DBNAME改为admin。

1
app.config['MONGO_DBNAME'] = "admin"

发现auth通过了,但是没数据了。因为连接的是admin数据库,而不是your_db。

源码分析

这里为了一探究竟,使用了PyCharm的自动跳转功能查看一下Flask-Pymongo配置部分的源码。初始化部分在init_app方法中。

可以看到这里面最开始用于验证的数据库就是admin,然后这里的if条件不成立,看下else是什么样子的。


这里可以看到,如果我们配置了MONGO_DBNAME,这里就会改变auth_database。


再往下看,我们可以看到这里MONGO_DBNAME如果没有设置的话,就会被设置成app.name。当然如果我们设置了MONGO_DBNAME,用于验证和连接的数据库都会变成MONGO_DBNAME。

所以经过分析,我们可以不使用MONGO_DBNAME,然后让DBNAME通过app.name来进行设置。

解决方法

最后的解决方法如下:

1
2
3
4
5
6
7
8
9
app = Flask(__name__)
app.name = "your_db"
# app.config['MONGO_DBNAME'] = "your_db" 不要这行了
app.config['MONGO_HOST'] = "localhost"
app.config['MONGO_PORT'] = "27017"
app.config['MONGO_USERNAME'] = "your_username"
app.config['MONGO_PASSWORD'] = "your_password"
mongo = PyMongo(app)

总结

有的时候看看源码还是蛮有用的,框架的源码不一定就很复杂。