Вступление
В предыдущем посте мы рассмотрели, как создать REST API с использованием инфраструктуры Java Spring Boot и MongoDB. API, однако, не требовал никакой аутентификации, а это значит, что он, вероятно, все еще не готов к использованию. Поэтому в этом руководстве будет рассказано, как использовать встроенную среду безопасности Spring для добавления уровня аутентификации в этот API.
Почему нашему api нужна аутентификация?
API предоставляют простой интерфейс для взаимодействия с внутренними данными, поэтому имеет смысл, чтобы вы не хотели, чтобы кто попало имел доступ к этим данным и их изменению. Аутентификация гарантирует, что только заслуживающие доверия пользователи смогут получить доступ к API.
Почему мы должны хешировать пароли?
Мы все слышали о недавних кибератаках, в результате которых у крупных компаний были украдены пароли. Так почему же рекомендуется только менять наши пароли после взлома? Потому что эти крупные компании позаботились о том, чтобы пароли всегда хешировались в их базах данных!
Хотя все-равно всегда стоит менять пароли после подобных взломов данных, хеширование паролей чрезвычайно затрудняет поиск реального пароля пользователя, поскольку оно является односторонним алгоритмом. Фактически, могут потребоваться годы, чтобы взломать сложный пароль хешированный должным образом.
3: удалённый доступ к mongodb (опционально)
В идеале базу данных MongoDB нужно блокировать внешним брандмауэром, который, в свою очередь, защищён с помощью виртуальной частной сети (VPN) или хоста-бастиона. Мы используем менее сложную настройку: настроим брандмауэр и разблокируем доступ к БД для заведомо безопасных хостов.
Bcrypt для хеширования паролей
Хеширование — это односторонний алгоритм шифрования. По сути, после хеширования практически невозможно обнаружить, как выглядели исходные данные. Алгоритм хэширования BCrypt сначала солит фрагмент текста, а затем хеширует его до строки длиной 60 символов. Кодировщик Java BCrypt предлагает метод
matches
, который проверяет, соответствует ли строка хешу. Например, пароль
p@55w0Rd
, хешированный с помощью BCrypt, может иметь значение
$2b$10$Qrc6rGzIGaHpbgPM5kVXdeNZ9NiyRWC69Wk/17mttHKnDR2lW49KS
. При вызове метода
matches
BCrypt для незашифрованного и хешированного пароля мы получим значение
true
. Эти хеши могут быть сгенерированы с помощью встроенного в Spring Security кодировщика BCrypt.
Prerequisites
To follow along with this guide, you’ll need an account on a MongoDB server with the appropriate privileges.
Required privileges
To execute the commands above, you need to login to MongoDB with an account with a number of different privilege actions. The specific privileges you require depend on the commands you need to use.
Включение ufw
Если вы следовали руководству по начальной настройке, вы уже включили брандмауэр UFW, который на данный момент поддерживает только соединения SSH. Прежде чем открыть порт для клиентов, проверьте состояние брандмауэра:
sudo ufw status
Примечание: Если по какой-либо причине брандмауэр не включен (inactive), запустите команду:
sudo ufw enable
Снова запросите состояние. При необходимости разблокируйте SSH.
sudo ufw allow OpenSSH
Команда sudo ufw status должна вернуть примерно следующее:
Status: activeTo Action From– —— —-OpenSSH ALLOW AnywhereOpenSSH (v6) ALLOW Anywhere (v6)
Разблокируйте стандартный порт MongoDB, 27017, но ограничьте доступ по ip, чтобы разрешить доступ только заведомо безопасным клиентам.
sudo ufw allow from client_ip_address to any port 27017
Чтобы добавить другие клиенты, запустите эту команду повторно, указав ip клиента. Чтобы убедиться, что доступ разблокирован, проверьте состояние брандмауэра:
sudo ufw statusTo Action From– —— —-OpenSSH ALLOW Anywhere27017 ALLOW client_ip_addressOpenSSH (v6) ALLOW Anywhere (v6)
Включение авторизации на mongodb
Прежде чем создать пользователя в mongodb, лучше включить авторизацию, для этого необходимо либо прописать в конфиге
security: authorization: enabled
Полный конфиг у нас будет выглядеть так
storage: dbPath: "/path/to/mongodata" systemLog: path: "/path/to/logs/mongod.log" logAppend: true destination: "file" net: bindIp : localhost processManagement: fork : true security: authorization: enabled
Либо запускать mongod с параметром —auth
mongod --auth
Если у вас не добавлено ни одного пользователя в mongodb, то после этого, вы сможете подключиться без авторизации только с localhost, для создания первого юзера. После создания первого юзера, вы не сможете подключится к серверу без авторизации даже с localhost. Это правильно называется Localhost Exception
Включение аутентификации
Чтобы запустить пользовательскую аутентификацию, необходимо внести изменения в конфигурационный файл MongoDB mongod.conf. Пока вы не сделаете это и не перезапустите службу MongoDB, пользователи будут подключаться к вашим базам данным без аутентификации.
Откройте для редактирования конфигурационный файл mongod.conf, например, при помощи текстового редактора nano:
$ cd /etc
$ sudo nano mongod.conf
В этом файле найдите строку #security и раскомментируйте её (удалите в начале строки символ #).
Следующей строкой добавьте текст:
authorization: enabled
Причём, необходимо убедиться, что в строке security нет никаких пробелов в её начале. Строка же authorization: enabled, напротив, имеет два пробела отступа в начале строки. Отредактированный текст должен выглядеть следующим образом:
После завершения редактирования сохраните изменения и закройте файл, для чего нажмите Ctrl X, затем Y и Enter.
Далее, необходимо перезапустить демон MongoDB для того, чтобы применились внесённые в конфигурацию изменения:
$ sudo systemctl restart mongod
Теперь запустите просмотр статуса службы:
$ sudo systemctl status mongod
Если перезапуск демона прошёл успешно, в выводе команды вы увидите, что служба mongod активна и находится в запущенном состоянии:
Теперь мы можем проверить, работает ли добавленный параметр аутентификации должным образом.
Добавление зависимостей безопасности
В корневом каталоге проекта должен быть файл с именем
pom.xml
. Мы еще не трогали этот файл, но файл pom содержит все зависимости нашего проекта, и мы собираемся добавить туда парочку, поэтому давайте начнем с открытия этого файла и прокрутки вниз до тега
Единственная новая зависимость, в которой мы нуждаемся, — это spring-starter-security. Spring имеет встроенный менеджер версий, поэтому зависимость, которую мы должны добавить в тег <dependencies>, следующая:
И Maven загрузит исходные файлы за нас, так что наши зависимости должны быть готовыми к работе!
Добавление кодировщика bcrypt
Теперь нам нужно сказать Spring, чтобы он использовал кодировщик BCrypt для хеширования и сравнения паролей — это звучит как трудная задача, но на самом деле это очень просто. Мы можем добавить этот кодировщик, просто добавив следующие строки в наш класс
SecurityConfiguration
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
И все дела! Этот простой бин сообщает Spring, что PasswordEncoder, который мы хотим использовать, — это Spring Boot
BCryptPasswordEncoder()
для кодирования и сравнения хешей паролей. Spring Boot также включает несколько других кодировщиков паролей — рекомендую попробовать их, если вы хотите поэкспериментировать!
Добавление модели пользователей и репозитория
В предыдущем посте подробно рассказывалось о моделях и репозиториях Mongo, поэтому я не буду здесь вдаваться в подробности о том, как они работают — если вы хотите освежить знания, не стесняйтесь посетить мой предыдущий пост!
Добавление пользователя в mongodb
Я добавлю минимум полей, необходимых для моей коллекции
Добавление юзера в mongodb без включенной авторизации
Если у вас еще не включена авторизация в конфиге, то вам достаточно присоединиться к mongodb
mongo
Как spring управляет безопасностью
Spring предлагает надстройку под названием
, которая делает аутентификацию легко настраиваемой и чрезвычайно простой. Мы даже можем использовать некоторые навыки, которые мы узнали в предыдущем посте, при настройке!
Как это работает
Мы будем использовать
Модель
Моделью будет базовый класс Java с пользовательскими
_id
Настройка bindip
Чтобы разрешить удаленные подключения, добавьте внешний IP-адрес хоста в файл mongod.conf .
sudo nano /etc/mongod.conf
В разделе net найдите строку bindIp и добавьте в неё IP хоста Mongo.
. . .net:port: 27017bindIp: 127.0.0.1,IP_of_MongoHost. . .
Сохраните и закройте файл.
Перезапустите демон:
sudo systemctl restart mongod
Убедитесь, что демон перезапустился без ошибок:
sudo systemctl status mongodb
Если всё прошло успешно, в выводе будет строка Active: active (running).
Подключение к оболочке mongodb
Для настройки будем использовать сервер, работающий под управлением Ubuntu 20.04. На сервере должен быть настроен брандмауэр при помощи UFW. Подключаться к серверу необходимо будет пользователем, имеющим привилегии sudo. Также, на сервере должен быть установлен пакет MongoDB версии 4.4.
Начиная с версии 3.0, служба MongoDB настроена только на приём подключений из локального Unix-сокета. При этом, аутентификация пользователей по умолчанию выключена, и любой пользователь, имеющий доступ к серверу, имеет доступ и к базе данных.
Первым шагом, для того, чтобы закрыть данную уязвимость, мы создадим административного пользователя. После чего, вы сможете включить пользовательскую аутентификацию и подключиться к базе данных под именем этой учётной записи, таким образом, получив доступ к ней.
Чтобы добавить административного пользователя, необходимо подключиться к оболочке Mongo. Так как пользовательская аутентификация отключена, вы можете сделать это используя команду mongo без каких-либо параметров:
$ mongo
Из-за того, что аутентификация всё ещё отключена, вывод выполнения команды будет содержать сообщения с предупреждением о том, что в Mongo не запущена система контроля доступа к базе данных, и доступ к чтению и записи данных и настроек базы не ограничен:
Эти предупреждения исчезнут, когда вы включите аутентификацию. Пока же следует иметь ввиду, что пользователь, получающий доступ к вашей операционной системе, также получает контроль и над вашими базами данных.
Чтобы увидеть это, в оболочке Mongo запустите следующую команду:
$ show dbs
Эта команда возвращает список всех баз данных Mongo на сервере:
Данный список должен выводится в зависимости от роли или уровня доступа к определённым базам, которые имеет пользователь Mongo, запускающий команду. Но поскольку аутентификация отключена, команда возвращает список всех баз данных без ограничений. Сейчас в этом списке присутствуют только базы, созданные Mongo по умолчанию.
Проверка аутентификации
Я протестирую быстрый
GET
-запрос с правильной и неправильной аутентификацией, чтобы убедиться, что конфигурация работает в соответствии с планом.
Неправильные Имя пользователя/Пароль
Проверка доступа администратора
Чтобы открыть сессию администратора, используйте опцию –u (задает имя пользователя) и –p (задаёт пароль). Также нужно добавить –authenticationDatabase, чтобы указать БД, в которой хранятся учётные данные.
Проверка параметров аутентификации
Теперь попробуем подключиться к оболочке Mongo. Мы сделаем это для того, чтобы протестировать, как работает система пользовательской аутентификации, которая была запущена в предыдущем разделе:
$ mongo
Как видите, при подключении к оболочке система больше не сообщает нам о том, что система контроля доступа к базам данных не запущена. Такие сообщения с предупреждениями вы могли видеть, когда подключались к оболочке в начале работ по настройке безопасности MongoDB. Из этого можно сделать вывод, что аутентификация включена.
Чтобы убедиться, что теперь доступ к базам ограничен, наберите:
$ show dbs
В отличие от того, как было раньше, когда эта команда возвращала список всех баз данных, теперь доступ к базам для вас закрыт, так как вы не авторизовались в Mongo как пользователь с каким-либо привилегиями.
И поскольку, какая-либо информация для вас теперь не доступна, мы можем заключить, что параметры аутентификации работают, как и ожидалось. Вы также не сможете создать пользователя или выполнить другие привилегированные задачи без авторизации в Mongo.
Теперь, отключитесь от оболочки, набрав exit, либо нажав Ctrl C.
Репозиторий
Репозиторий будет называться
Репозиторий mongodb
База данных MongoDB включена в репозиторий пакетов Ubuntu, но официальный репозиторий MongoDB предлагает более актуальную версию. Итак, для начала нужно добавить официальный репозиторий.
Ubuntu проверяет подлинность пакетов программного обеспечения с помощью ключей GPG. Импортируйте ключ официального репозитория MongoDB.
Создание администратора
Чтобы добавить пользователя, подключитесь к оболочке Mongo.
mongo
В выводе вы увидите предупреждение, что контроль доступа отсутствует, то есть доступ к базе данных и конфигурациям ничем не ограничен.
Создание конфигурации безопасности
src/main/resources/java/[package name]
с именем
config
, и мы также должны создать новый файл в этой папке конфигурации с именем
SecurityConfiguration.java
. Этот файл имеет несколько важных частей, поэтому давайте начнем с базового класса SecurityConfiguration:
Создание пользователя mongodb с включенной авторизацией
Для того, чтобы создать пользователя с включенной авторизацией, но без единого пользователя в бд, убедитесь что у вас в конфиге установлено
net: bindIp : locahost
Далее подключитесь к mongodb
mongo
Создание службы аутентификации
Нам нужно сообщить Spring, где находятся наши пользовательские данные и где найти информацию, необходимую для аутентификации. Для этого мы можем создать службу аутентификации (Authentication Service). Давайте начнем с создания новой папки в
src/main/resources/java/[package name]
под названием services, и мы можем создать новый файл в этой папке конфигурации с именем
Тестирование аутентификации
Попробуйте подключиться к БД без учётных данных.
mongo
После включения аутентификации все предупреждения исчезают:
MongoDB shell version v3.4.2connecting to: mongodb://127.0.0.1:27017MongoDB server version: 3.4.2
Вы подключились к БД test. Теперь попробуйте запустить какую-нибудь команду:
Требования
- Сервер Ubuntu 16.04.
- Пользователь с доступом к sudo (вся работа выполняется в его сессии).
- Настроенный брандмауэр.
Всю необходимую информацию вы найдёте в руководстве по начальной настройке сервера.
Указание диспетчера аутентификации
Наконец, мы должны указать в нашей
SecurityConfiguration
, что мы хотим использовать
Установка mongodb
Установите метапакет mongodb-org, который включает в себя демон, конфигурационные сценарии и сценарии инициализации, оболочку и инструменты управления.
sudo apt-get install mongodb-org
По запросу нажмите Enter или Y. После установки запустите демон Mongo:
sudo systemctl start mongod
Поскольку systemctl не выводит результат этой команды, нужно запросить состояние демона, чтобы убедиться, что он запущен.
Этап аутентификации
Далее нам нужно сообщить Spring Security, как мы хотим обрабатывать аутентификацию пользователей. По умолчанию Spring Security имеет предопределенные имя пользователя и пароль,
. Однако мы хотим, чтобы наши пользователи использовали свое имя пользователя и пароль для доступа к базе данных. Кроме того, поскольку наши пользователи будут проходить повторную аутентификацию при каждом запросе, а не входить в систему, CSRF Protection и управление сеансами нам не нужны, поэтому мы можем добавить метод с именем
configure
, который переопределяет схему аутентификации по умолчанию, чтобы сообщить Spring, как именно мы хотим обрабатывать аутентификацию, и будет выглядеть следующим образом:
Заключение
Теперь вы умеете устанавливать MongoDB, обеспечивать безопасность данных и настраивать поддержку удалённых соединений.