Devahoy Logo
PublishedAt

Web Development

มาทำให้ MongoDB ปลอดภัยขึ้นด้วยการ Enable Auth กันดีกว่า

มาทำให้ MongoDB ปลอดภัยขึ้นด้วยการ Enable Auth กันดีกว่า

เนื่องจากว่าวันนี้ได้อ่านเจอบทความเกี่ยวกับ MongoDB จากนี้ ฐานข้อมูล MongoDB ถูกเจาะเป็นจำนวนมาก ข้อมูลถูกล้างและเรียกค่าไถ่ แล้วรู้สึกว่า โอ้โห! Default ของ MongoDB ไม่ได้กำหนด Auth มาให้ ทำให้ user ไหน ก็สามารถ access เข้า database ของเราก็ได้นี่หว่า

วิธีแก้ นี่เลยครับ supo apt-get uninstall mongodb-org ลบมันทิ้งเลย ทีนี้ก็จะไม่โดนเจาะแล้ว ต้องแก้ด้วยต้นเหตุ เราจะแก้ด้วยปลายเหตุด้วยการ config ให้เสียเวลาทำไม ฉลาดไหม

.

.

.

จะบ้าเหรอ!!

ก็เลยลองนั่งไลๆ่อ่าน MongoDB Security Checklist ของทาง MongoDB รู้สึกว่ามันน่าจะมีประโยชน์ ก็เลยเขียนเป็นบทความมาแชร์กันครับ

Environment

Terminal window
- Ubuntu 16.04
- MongoDB 3.4.1

1. Start MongoDB

เริ่มต้น หากว่า MongoDB ไม่ได้รันอยู่ ก็สั่งรันได้ด้วยคำสั่ง

Terminal window
$ sudo service mongod start
หรือ
$ mongod

ลองตรวจสอบ สถานะดูด้วยคำสั่ง

Terminal window
$ sudo service mongod status
mongod.service - High-performance, schema-free document-oriented database
Loaded: loaded (/lib/systemd/system/mongod.service; disabled; vendor preset: enabled)
Active: active (running) since Sun 2017-01-08 10:25:41 UTC; 3s ago
Docs: https://docs.mongodb.org/manual
Main PID: 1958 (mongod)
Tasks: 17
Memory: 32.0M
CPU: 574ms
CGroup: /system.slice/mongod.service
└─1958 /usr/bin/mongod --quiet --config /etc/mongod.conf

หากว่า MongoDB รันแล้ว ก็ลองทดสอบด้วยการ shell เข้าไปดูด้วยคำสั่ง

Terminal window
$ mongo
MongoDB shell version v3.4.1
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.1
>

2. Create Admin user

ต่อมา เมื่อ shell เข้าด้วย Mongo Shell แล้ว ก็มาทำการสร้าง User ที่เป็น Administrator กันดีกว่า

Terminal window
$ mongo
> show dbs
admin 0.000GB
local 0.000GB
> use admin
switched to db admin

จากนั้นทำการสร้าง User Administrator ขึ้นมา

Terminal window
> db.createUser(
... {
... user: 'superAdmin',
... pwd: 'superPassword',
... roles: [ { role: 'root', db: 'admin' } ]
... }
... )

ใน mongo shell เราสามารถพิมพ์คำสั่งหรือ statement แล้วกด enter ได้เลย จะขึ้น … ไม่ต้องตกใจ ตัว shell มันจะไม่ execute จนกว่าจะหมด statement นะครับ

หากว่าทำการ create user เสร็จ จะได้ผลลัพธ์แบบนี้

Terminal window
Successfully added user: {
"user" : "superAdmin",
"roles" : [
{
"role" : "root",
"db" : "admin"
}
]
}

อธิบายด้านบนคือ เราทำการสร้าง user ชื่อ “superAdmin” และมี role เป็น “userAdminAnyDatabase” และ grant db ไว้ที่ db ชื่อ “admin”

ซึ่ง user นี้เราจะเอาไว้สำหรับจัดการ User อื่นๆ (Add/Edit/Update)

สำหรับ Role ต่างๆ ของ MongoDB ก็อ่านเพิ่มเติมที่ Built-in Roles ส่วน “root” คร่าวๆ ก็รวมๆ roles ต่างๆ ทุกอย่างเลย เช่น readWriteAnyDatabase, dbAdminAnyDatabase, userAdminAnyDatabase, clusterAdmin roles, restore, และ backup

3. Enable Authorization

ต่อมา ตัว MongoDB นั้นเริ่มต้นมา จะไม่ได้ปิด Auth ทำให้ เราสามารถ access ได้โดยไม่ต้องใช้ user/pass ให้ทำการ enable Authorization ซะ โดย ทำการแก้ไขไฟล์ /etc/mongod.conf

Terminal window
sudo vi /etc/mongod.conf

จากนั้นเพิ่มส่วน security ดังนี้

Terminal window
security
authorization: enabled

เซฟ แล้วลอง restart mongo ใหม่

Terminal window
sudo service mongod restart

Note: นอกจาก authorization: enabled แล้ว เรายังสามารถเปลียน default port นอกจาก 27017 ก็ได้ รวมถึงดูว่า เราได้ปรับ bindIp ไว้หรือเปล่า bindIp: 127.0.0.1 เพื่อให้สามารถ connect เฉพาะ localhost ได้อย่างเดียว ที่อื่นจะ remote access เข้ามาไม่ได้

ทีนี้ลองเข้า Mongo ใหม่ดู

Terminal window
$ mongo
> show dbs
2017-01-08T10:48:51.823+0000 E QUERY [main] Error: listDatabases failed:{
"ok" : 0,
"errmsg" : "not authorized on admin to execute command { listDatabases: 1.0 }",
"code" : 13,
"codeName" : "Unauthorized"
}
> use anotherDb
switched to db anotherDb

จะเห็นว่าเราไม่สามารถจะใช้คำสั่งได list database ได้แล้ว เนื่องจากไม่มี permission นั่นเอง แต่ยังสามารถ switch db ได้ แต่ก็ไม่มีสิทธิ์ทำอะไรอีกนั่นแหละ หากเราตั้งค่าไว้

ต้องทำการเข้าด้วย user pass ของ admin ดังนี้

Terminal window
$ mongo -u 'superAdmin' -p 'superPassword' --authenticationDatabase 'admin'
>
  • -u 'username' : สำหรับใส่ username
  • -p 'password' : สำหรับใส่ password
  • --authenticationDatabase 'db' : สำหรับ db ที่เราต้องการ access

Note: เราสามารถใส่ -p แล้วเว้น password ไว้ได้เพื่อใส่ Password ทีหลัง จะได้ไม่เซฟ password ของเราไว้กับ bash/zsh history นั่นเอง

4. Create New User

ต่อมา เรามาสร้าง User เพื่อเอาไว้สำหรับ connect MongoDB แต่จะกำหนดแค่ว่า user คนนี้ สามารถเข้าได้แค่ database นั้นๆ เท่านั้น โดยให้สิทธิ์เป็น “readWrite” คือสามารถ อ่านและเขียน (Read/Insert db) ได้

Terminal window
$ mongo -u 'superAdmin' -p 'superPassword' --authenticationDatabase 'admin'
# access เข้า myDatabase
> use myDatabase;
db.createUser({
user: 'chai',
pwd: 'superPassword',
roles: ['readWrite']
})
Successfully added user: { "user" : "chai", "roles" : [ "readWrite" ] }

หรือว่าเราจะใช้คำสั่ง ด้านล่างนี้ เพื่อกำหนดให้ user มีสิทธิ์ใน database อื่นก็ได้

1
db.createUser({
2
user: 'chai',
3
pwd: 'superPassword',
4
roles: [{ role: 'readWrite', db: 'anotherDatabase' }]
5
})

ลองเช็คดูว่ามี user จริงๆไหม

Terminal window
> show dbs
admin 0.000GB
local 0.000GB
> use admin
switched to db admin
> show collections
system.users
system.version
> db.system.users.find().pretty()
{
"_id" : "myDatabase.chai",
"user" : "chai",
"db" : "myDatabase",
"credentials" : {
"SCRAM-SHA-1" : {
"iterationCount" : 10000,
"salt" : "8QS....",
"storedKey" : "Scn...",
"serverKey" : "w2j..."
}
},
"roles" : [
{
"role" : "readWrite",
"db" : "myDatabase"
}
]
}

5. Connect with mongoose

ทีนี้ลองมา Connect MongoDB ด้วยโปรแกรมดู ด้านล่างนี้ใช้ Mongoose.js สร้างไฟล์ชื่อ app.js

โดยที่ไม่ใส่ User Password เวลา connect

1
const mongoose = require('mongoose')
2
3
const URL = 'mongodb://localhost/myDatabase'
4
5
function callback(err, result) {
6
if (err) {
7
throw err
8
}
9
}
10
11
mongoose.connect(URL, callback)
12
13
let Cat = mongoose.model('Cat', { name: String })
14
15
let kitty = new Cat({ name: 'Jane' })
16
kitty.save(function (err) {
17
if (err) {
18
console.log(err)
19
} else {
20
console.log('meow')
21
}
22
})

ลองสั่งรันดู

Terminal window
$ node app.js
{ MongoError: not authorized on simple_auth to execute command { insert: "cats", documents: [ { name: "Jane",
...
...
name: 'MongoError',
message: 'not authorized on simple_auth to execute command { insert: "cats", documents: [ { name: "Jane", _id: ObjectId(\'5872208dff5e220f6d37e217\'), __v: 0 } ], ordered: false, writeConcern: { w: 1 } }',
ok: 0,
errmsg: 'not authorized on simple_auth to execute command { insert: "cats", documents: [ { name: "Jane", _id: ObjectId(\'5872208dff5e220f6d37e217\'), __v: 0 } ], ordered: false, writeConcern: { w: 1 } }',
code: 13,
codeName: 'Unauthorized' }

ต่อมาเปลี่ยนใหม่ ตอน connect ให้ใส่ options สำหรับ user/pass ไปด้วย เพื่อจะได้ Auth ผ่าน

1
const options = {
2
user: 'chai',
3
pass: 'superPassword'
4
}
5
6
mongoose.connect(URL, options, callback)

ลองรันใหม่

Terminal window
$ node app.js
meow

เป็นอันเรียบร้อย ตอนนี้เราก็ Enable Auth แล้ว หวังว่า Database เราจะ Security ขึ้นมาอีกระดับนะครับ :)

โค๊ดทั้งหมด app.js

1
const mongoose = require('mongoose')
2
3
const URL = 'mongodb://localhost/myDatabase'
4
const options = {
5
user: 'chai',
6
pass: 'superPassword'
7
}
8
9
function callback(err, result) {
10
if (err) {
11
throw err
12
}
13
}
14
15
mongoose.connect(URL, options, callback)
16
17
let Cat = mongoose.model('Cat', { name: String })
18
19
let kitty = new Cat({ name: 'Jane' })
20
kitty.save(function (err) {
21
if (err) {
22
console.log(err)
23
} else {
24
console.log('meow')
25
}
26
})

References

Authors
avatar

Chai Phonbopit

เป็น Web Dev ในบริษัทแห่งหนึ่ง ทำงานมา 10 ปีกว่าๆ ด้วยภาษาและเทคโนโลยี เช่น JavaScript, Node.js, React, Vue และปัจจุบันกำลังสนใจในเรื่องของ Blockchain และ Crypto กำลังหัดเรียนภาษา Rust

Related Posts