Я недавно обновил mongometer, чтобы сделать его немного более гибким. Вскоре после выпуска новой версии один из пользователей сообщил о проблеме через комментарий к сообщению. Я загрузил свою машину, открыл IDE, обнаружил проблему и через полчаса отправил исправление на github . Это не быстрый поворот, пост истории успеха. Меня быстро осенило, что если я собираюсь что-то делать в будущем с помощью mongometer, я действительно должен знать немного больше о том, как пользователь аутентифицируется в базе данных в MongoDB. (Я не хочу тратить на это больше часа, потому что я только что взломал бутылку Nyetimber Classic Cuvee — я также готовлю пирог с курицей (пингуйте меня, если хотите рецепт), и я Я предпочел бы закончить этот пост, прежде чем я закончу бутылку.) Прежде чем углубляться в какую-либо документацию, которая может существовать вокруг безопасности MongoDB, я начну с нескольких наблюдений.
Итак, в типичном мужском стиле давайте пинаем шины, а затем, если потребуется, RTFM. Запустите Mongod.
1
2
|
$ /usr/lib/mongodb/2 .3.2 /bin/mongod --port 27001 --fork --dbpath /data/db/2 .3.2 --logpath /data/db/2 .3.2 /mongod .log $ . /mongo --port 27001 |
Создать администратора
1
2
3
|
> use admin > db.addUser( 'mongouser' , 'mongopass' ) 1 |
Перезапустите Mongod
1
2
3
|
$ sudo kill -15 $( ps -ef | grep mongo | grep - v grep | cut -f8 -d ' ' ) $ /usr/lib/mongodb/2 .3.2 /bin/mongod --port 27001 --fork --auth --dbpath /data/db/2 .3.2 --logpath /data/db/2 .3.2 /mongod .log $ . /mongo --port 27001 |
Аутентификация для администратора
1
2
3
4
5
6
|
> use admin switched to db admin > db.aut( 'mongouser' , 'mongopass' ) Thu Jan 31 13:53:31.271 javascript execution failed (shell):1 TypeError: Property 'aut' of object admin is not a function db.aut( 'mongouser' , 'mongopass' ) ^ |
1
|
> db.aut( 'mongouser' , 'mongopass' ) |
По электронной почте Ой. Толстяк это. Подожди, я думаю, что нашел проблему № 1
№ 1
Если пользователь с правами администратора вводит неверную команду auth, а не учетные данные, то фактические учетные данные остаются в истории оболочки, которая сохраняется в сеансах. Любой другой пользователь может прийти и просмотреть историю оболочки и получить учетные данные.
С другой стороны, если команда верна и либо имя пользователя или пароль, либо оба неверны, или действительно, если попытки аутентификации завершаются успешно, команда не сохраняется в истории. (История команд для оболочки mongo доступна так же, как и для Linux, при использовании стрелки вверх)
1
2
3
4
5
6
7
8
9
|
> db.auth( 'mongouser' , 'mongopass0' ) { ok: 0.0, errmsg: 'auth fails' } 0 > db.auth( 'mongouser0' , 'mongopass0' ) { ok: 0.0, errmsg: 'auth fails' } 0 > db.auth( 'mongouser0' , 'mongopass' ) { ok: 0.0, errmsg: 'auth fails' } 0 |
ОК. Давайте аутентифицироваться против администратора и продолжим.
1
2
3
4
|
> use admin switched to db admin > db.auth( 'mongouser' , 'mongopass' ) 1 |
Oooops. Я почти пропустил один там.
Выпуск № 2
Пока экземпляр mongod не будет перезапущен, любой пользователь может …
1
2
3
4
|
> use admin switched to db admin > db.system. users . find () { '_id' : ObjectId( '510a58c6de50e136190f9ed7' ), 'user' : 'mongouser' , 'readOnly' : false , 'pwd' : 'c49caa1cb6b287ff6b1deaeeb8f4d149' } |
… захватить имена пользователей и хэши. Итак, теперь, когда я перезапустил экземпляр mongod, любой пользователь должен будет пройти аутентификацию на уровне администратора, чтобы иметь возможность просматривать содержимое system.users . Теперь, продолжая ввод неправильных учетных данных, я собираюсь запустить атаку по словарю и посмотреть, что произойдет. О, Боже. Нашел еще одну проблему.
Выпуск № 3
Там нет локаут. Я написал быстрый хак, чтобы подключиться к экземпляру mongod, переключиться на admin и попытаться войти в систему. Используя довольно большой словарь (с прикрепленным «mongopass» в конце), я пытался войти в систему более миллиона раз. Это была только грубая однопотоковая попытка, которая заняла около 17 секунд, но она показывает, что блокировка учетной записи отсутствует. Я уверен, что смогу собрать многопоточный брутфорсер, если потребуется. Мне нужно изучить это далее, чтобы увидеть, есть ли какое-либо грубое принуждение / предупреждение о словарной атаке, которое можно настроить, или есть ли политика блокировки, которая может быть применена. Я пока не готов к RTFM. Давайте подробнее рассмотрим формат пароля в system.users .
1
|
c49caa1cb6b287ff6b1deaeeb8f4d149 |
Это выглядит как MD5 для меня. Давайте посмотрим на код, который доступен для круиза на github . Вот Это Да! Я получил удачу сразу. db.js имеет следующий метод:
1
2
3
|
function _hashPassword(username, password) { return hex_md5(username + ':mongo:' + password); } |
Затем с помощью hex_md5 ссылается на native_hex_md5 в utils.cpp :
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
void installGlobalUtils( Scope& scope ) { scope.injectNative( 'hex_md5' , native_hex_md5 ); scope.injectNative( 'version' , native_version ); scope.injectNative( 'sleep' , native_sleep ); installBenchmarkSystem( scope ); } static BSONObj native_hex_md5( const BSONObj& args, void * data ) { uassert( 10261 , 'hex_md5 takes a single string argument -- hex_md5(string)' , args.nFields() == 1 && args.firstElement().type() == String ); const char * s = args.firstElement().valuestrsafe(); md5digest d; md5_state_t st; md5_init(&st); md5_append( &st , ( const md5_byte_t*)s , strlen( s ) ); md5_finish(&st, d); return BSON( '' << digestToString( d ) ); } |
Время для быстрого резюме. На всякий случай, если вы что-то пропустили:
- алгоритм хеширования — MD5 ; мой наименее любимый алгоритм хеширования.
- хешируемая строка имеет вид
username + ':mongo:' + password
; использование той же «соли» неоптимально… - строка
:mongo:
является глобальной; Я не совсем уверен, почему это там вообще.
Я думаю, что этого, вероятно, достаточно, чтобы пойти сейчас, иначе это превратится в тролля, и я могу превзойти свои собственные временные ограничения. Возвращаясь к любым обсуждениям, которые у меня были в отношении MongoDB, одни и те же заявления всегда возникали в контексте безопасности.
- Аутентификация по умолчанию отключена.
- MongoDB всегда предназначался для развертывания в надежной среде
Я должен сказать, что даже при включенной аутентификации у нас все еще есть некоторые грубые проблемы. Кроме того, я не думаю, что существует надежная среда . Прямо тогда, время RTFM относительно безопасности. Я надеюсь найти определенную дорожную карту, которая будет иметь дело с вышеупомянутыми проблемами, или уже есть некоторые смягчающие шаги, которые могут быть предприняты. Итак, в ближайшем будущем появятся некоторые функции аутентификации . Похоже, что новые функции аутентификации доступны только в MongoDB Subscriber Edition , я не уверен, что это означает, что tbh … Я также столкнулся с этой проблемой , которая лежит в основе …
Выпуск № 4
‘если у пользователя один и тот же пароль в нескольких базах данных, хеш будет одинаковым во всех базах данных. Злоумышленник может использовать это для получения доступа ко второй базе данных, используя учетные данные других пользователей. [sic] Давайте разберемся с этим.
«Если у пользователя один и тот же пароль в нескольких базах данных, хеш будет одинаковым во всех базах данных».
Да. Верный. То же имя пользователя, тот же пароль и та же «соль» (т. Е. «: Mongo:« строка ») равны тому же хешу. ОК, круто, давайте двигаться дальше.
«Злоумышленник может использовать это для получения доступа ко второй базе данных, используя учетные данные других пользователей». [Так в оригинале]
Злоумышленник может использовать это в том и только в том случае, если у него есть пользователь, не имеющий права чтения, в обеих задействованных базах данных.
Если они имеют доступ только для чтения, они не могут перечислить коллекцию system.users . В этом случае они никогда не увидят, что хэши одинаковы для разных баз данных. Если они не доступны только для чтения, они могут перечислить коллекцию system.users и перевести хэшированные пароли в автономный режим для взлома.
Вам нужно будет перейти на взломанную территорию, если хэши не совпадают в разных базах данных, в итоге:
- атрибут пользователя был бы таким же. Шансы разных пользователей на разные базы данных, имеющие пользователя, могут быть высокими.
- атрибут pwd был бы таким же. Вероятность того, что разные пользователи создадут один и тот же pwd, довольно высока.
- «соль» такая же, поэтому здесь она не имеет никакого отношения к делу.
Таким образом, проблема в том, что пользователь (который не только для чтения) может извлечь все хэши паролей для данной базы данных и перевести их в автономный режим для взлома. Злоумышленник уже имеет имя пользователя и «соль», все, что ему нужно найти, — это пароль.
Выводы
№ 1
Это немного больно. Когда команда введена правильно (игнорируя правильность учетных данных или нет), команда не отображается в истории. Когда команда введена неправильно, трудно понять, что нужно исключить из истории команд. Я думаю, вы могли бы ретроспективно удалить команды, которые привели к ошибкам (то есть недопустимые команды), которые предшествовали аутентификации. Это не решение …
Выпуск № 2
Может быть аргумент, что после создания пользователя admin в system.users в базе данных admin , перезапуск должен быть принудительным.
Выпуск № 3
Понятно. Я несколько раз писал политики паролей (какая веселая жизнь, да?), Блокировка учетной записи — это пароль 101.
Выпуск № 4
Кажется, что создание ‘salt’ (‘: mongo:’) для базы данных решило бы проблему. Глядя на код, кажется, что реализация — пустяк, быстрый и легкий выигрыш. Добавление опции для ручной настройки было бы грандиозным. Реализация уникальной «соли» под прикрытием, чтобы пользователям не приходилось думать об этом, была бы столь же грандиозной. Итак, Nyetimber закончил, запись закончена. Я не говорю, что в этом посте есть что-то новое или умное, это беглый взгляд. Я не собираюсь идти; все, что я упомянул, это просто наблюдение. Я устанавливаю монго почти ежедневно, потому что это отличный продукт, однако мне нравится иметь сбалансированный обзор и выявлять слонов в комнате. Я был бы заинтересован в любой обратной связи.
Ссылка: Аутентификация MongoDB от нашего партнера JCG Яна Эттлса в блоге Исключительно исключительных ситуаций.