Хранение паролей всегда было головной болью. В классическом варианте у вас есть пользователь, который очень старается не забыть жутко секретный «qwerty123» и информационная система, которая хранит хеш от этого пароля. Хорошая система еще и заботливо солит хеши, чтобы отравить жизнь нехорошим людям, которые могут украсть базу с хешированными паролями. Тут все понятно. Какие-то пароли храним в голове, а какие-то засовываем в зашифрованном виде в keepass.
Все меняется, когда мы убираем из схемы человека, который старательно вводит ключ с бумажки. При взаимодействии двух информационных систем, на клиентской стороне в любом случае должен храниться пароль в открытом для системы виде, чтобы его можно было передать и сравнить с эталонным хешем. И вот на этом этапе админы обычно открывают местный филиал велосипедостроительного завода и начинают старательно прятать, обфусцировать и закапывать секретный ключ в коде скриптов. Многие из этих вариантов не просто бесполезны, но и опасны. Я попробую предложить удобное и безопасное решение этой проблемы для python. И чуть затронем powershell.
Как делать не надо
Всем знакома концепция «временного скриптика». Вот буквально только данные по-быстрому распарсить из базы и удалить. А потом внезапно выясняется, что скрипт уже из dev-зоны мигрировал куда-то в продакшен. И тут начинают всплывать неприятные сюрпризы от изначальной «одноразовости».
Чаще всего встречается вариант в стиле:
db_login = 'john.doe'
password = 'password!'
Проблема в том, что здесь пароль светится в открытом виде и достаточно просто обнаруживается среди залежей старых скриптов автоматическим поиском. Чуть более сложный вариант идет по пути security through obscurity, с хранением пароля в зашифрованном виде прямо в коде. При этом расшифровка обратно должна выполняться тут же, иначе клиент не сможет предъявить этот пароль серверной стороне. Такой способ спасет максимум от случайного взгляда, но любой серьезный разбор кода вручную позволит без проблем вытащить секретный ключ. Код ниже спасет только от таких «shoulder surfers»:
>>> import base64
>>> print base64.b64encode("password")
cGFzc3dvcmQ=
>>> print base64.b64decode("cGFzc3dvcmQ=")
password
Самый неприятный сценарий — использования систем контроля версии, например git, для таких файлов с чувствительной информацией. Даже, если автор решит вычистить все пароли — они останутся в истории репозитория. Фактически, если вы запушили в git файл с секретными данными — можете автоматически считать их скомпрометированными и немедленно начинать процедуру замены всех затронутых credentials.
Использование системного хранилища
Есть крутейшая библиотека keyring. Основной принцип работы строится на том, что у каждого пользователя ОС есть свое зашифрованное хранилище, доступ к которому возможен только после входа пользователя в систему. Она кроссплатформенная и будет использовать тот бэкенд для хранения паролей, который предоставлен операционной системой:
- KDE4 & KDE5 KWallet (требуется dbus)
- Freedesktop Secret Service — множество DE, включая GNOME (требуется secretstorage)
- Windows Credential Locker
- macOS Keychain
Также можно использовать альтернативные бэкенды или написать свой, если уж совсем что-то странное требуется.
Сравним сложность атаки
При хранении пароля непосредственно в скрипте нужно:
- Похитить сам код (легко)
- Деобфусцировать при необходимости (легко)
При использовании локального keyring злоумышленнику нужно:
- Похитить сам код (легко)
- Деобфусцировать при необходимости (легко)
- Скомпрометировать локальную машину, залогинившись под атакуемым пользователем (сложно)
Теоретически, доступ к локальному хранилищу сможет получить любая локальная программа, работающая от имени текущего пользователя, если будет знать параметры доступа к секретному паролю. Однако, это не является проблемой, так как в случае компрометации учетной записи злоумышленник и так сможет перехватить все чувствительные данные. Другие пользователи и их ПО не будет иметь доступа к локальному хранилищу ключей.
Пример использования
import argparse
import getpass
import keyring
def parse_arguments():
parser = argparse.ArgumentParser()
parser.add_argument("-n", "--newpass", required=False, help="Set new password", action="store_true")
arguments = parser.parse_args()
return arguments
def fake_db_connection():
# Функция, имитирующая подключение к базе данных или что-то подобное
db_name = 'very_important_db'
db_host = '147.237.0.71'
passwd = keyring.get_password(systemname, username)
print('Connecting to db: {}'.format(db_name))
print('Using very secret password from vault: {}'.format(passwd))
print('Doing something important...')
print('Erasing the database...')
print('Task completed')
# Объявляем дефолтные переменные
systemname = 'important_database'
username = 'meklon'
args = parse_arguments()
# Записываем в хранилище пароль, если активирован параметр --newpass
if args.newpass:
# Безопасно запрашиваем ввод пароля в CLI
password = getpass.getpass(prompt="Enter secret password:")
# Пишем полученный пароль в хранилище ключей
try:
keyring.set_password(systemname, username, password)
except Exception as error:
print('Error: {}'.format(error))
# Подключаемся к базе с помощью пароля из системного хранилища
fake_db_connection()
Безопасный ввод пароля
Еще один частый вариант утечки секретных паролей — история командной строки. Использование стандартного input здесь недопустимо:
age = input("What is your age? ")
print "Your age is: ", age
type(age)
>>output
What is your age? 100
Your age is: 100
type 'int'>
В примере выше я уже упоминал библиотеку getpass:
# Безопасно запрашиваем ввод пароля в CLI
password = getpass.getpass(prompt="Enter secret password:")
Ввод данных при ее использовании аналогичен классическому *nix подходу при входе в систему. Ни в какие системные логи данные не пишутся и не отображаются на экране.
Немного о Powershell
Для Powershell правильным вариантом является использование штатного Windows Credential Locker.
Реализуется это модулем CredentialManager.
Пример использования:
Install-Module CredentialManager -force
New-StoredCredential -Target $url -Username $ENV:Username -Pass ....
Get-StoredCredential -Target ....
Комментарии (81)
virtual_hack2root
14.01.2019 11:57+1Я думаю, что стандартный, подход в DevOps заколючется как раз не в раскрытии приватной информации, с последующей ее защитой с помощью keyring, а в том, чтобы изначально параметризовать скрипты, (причем — любые: bash, powershell, python, Docker, и т.д.), с помощью настраиваемых переменных окружения, и предоставлении доступа к ним через Web IDE / Web UI и программный доступ по API для параметризации. Данный подход реализован в GitLab, Azure, Google Cloud, Digital Ocean, GitHub
Meklon
14.01.2019 11:59Подожди, ну вот у нас есть взаимодействие Machine2Machine. Одна сторона у тебя в любом случае должна иметь пароль. Оператора, который вобьет его интерактивно нет. Пароль в виде параметра скрипта как-то несекьюрно использовать. Как минимум будет светиться в history.
virtual_hack2root
14.01.2019 12:01+1Не будет, так так там будет светиться что-то вроде ${CI_GITLAB_PASSWORD}, а не пароль, а само значение ${CI_GITLAB_PASSWORD} можно забить как на источнике так и на целевой машине.
Meklon
14.01.2019 12:02А CI_GITLAB_PASSWORD где физически хранится?
virtual_hack2root
14.01.2019 12:03в переменных окружения для выполняемого процесса
Meklon
14.01.2019 12:14А переменные привязаны к локальной машине?
virtual_hack2root
14.01.2019 12:28Нет, это завилит от конкретого pipeline, и CI, они настраиваются в конфигураторе конкретного CI, и фактически работают внутри контейнера, и могут располагаться как в облаке, так и на конкретной машине, на которой запущен агент CI, то есть это полностью зависит от того, как сконфигурирован конкретный агент (Azure, GitlLab, Jenkins позволяют установку локальных агентов не в облако а на конкретную машину, в зависимости от настроек агента, агент может либо требовать совместную настройку Docker-а, если работает в режиме ВМ, Docker/Docker Swarm ноды/ ноды кластера Kubertenes (GlitLab), либо нет, если работает в режиме remote shell, с прямым доступом к локальной оболочке ОС), так что с точки зрения Azure, GitHub и Google Cloud, происходит передача информации ("возьми пароль из переменной окружения x для подключения к БД у") вместо ("возьми пароль x для подключения к БД у")
Пример (там есть пример настройки БД):
Testing a Phoenix application with GitLab CI/CD
Обрати внимение на
variables: POSTGRES_DB: test_test POSTGRES_HOST: postgres POSTGRES_USER: postgres POSTGRES_PASSWORD: "postgres" MIX_ENV: "test"
их можно заменить на переменные окружения
variables: POSTGRES_DB: $CI_POSTGRES_DB POSTGRES_HOST: $CI_POSTGRES_HOST POSTGRES_USER: $CI_POSTGRES_USER POSTGRES_PASSWORD: $CI_POSTGRES_PASSWORD MIX_ENV: $CI_MIX_ENV
Meklon
14.01.2019 12:59Ага, спасибо, почитаю. Хотя, имхо, сложность компрометации эквивалентна варианту с keyring.
skovpen
15.01.2019 17:22и что произойдёт, если в пуллреквесте будет в CI-скрипте добавлена строчка злоумышленником?
echo $CI_POSTGRES_PASSWORD
gecube
15.01.2019 17:32Вы просто мерж реквест не принимаете и все довольны.
skovpen
15.01.2019 17:35+1Много Вы проектов видели, где пуллреквест проверяется CI только после ручного просмотра?
gecube
15.01.2019 17:41Вы имеете в виду, что пуллреквест тоже прогоняется через CI — и это риск утечки данных?
Ну, да, есть такое, но проблема в Gitlab (одно из решений) решается следующими способами:
- переменную можно объявить как protected
- это дает возможность видеть ее ТОЛЬКО на protected runner (нужно их завести и пометить)
- и нужно пометить ветки как protected и назначить права на пользователей (кто куда может пушить код).
- далее аккуратно принимать мерж реквесты.
Ну, и коли Вы не доверяете своей команде разработчиков, которая и так скорее всего имеет доступ на продакшн и может залить любой вредоносный код (гораздо посерьезнее, чем просто отображение пароля к продовой базе), то у Вас проблемы ГОРАЗДО более серьезные, чем утечка паролей...
worldmind
14.01.2019 18:30И кто устанавливает эти переменные окружения?
Если конфиг с открытым паролем, то это хуже предложенного способа.virtual_hack2root
14.01.2019 18:53+1пароли устанавливает тот же человек, который настраивает пайплайн сборки, но не в скриптах, а в переменных окружения, используемых при сборке, взаимодействие узлов может осуществляеться в таком случает через использование пременных окружения из защифроманной памяти виртуальной машины (Google Cloud).
worldmind
14.01.2019 19:25> а в переменных окружения, используемых при сборке
это только ждля случая с докером годиться
Tangeman
14.01.2019 22:51Если конфиг с открытым паролем, то это хуже предложенного способа.
Если у злоумышленника есть доступ к конфигу которого нет в репозитории, то это гораздо серьезней проблемы с паролями.
Sap_ru
14.01.2019 18:47+6Тут есть проблема, что переменные наслеются все дочерними процессами и пароли легко утекают в совершенно непредсказуемые дыры. А ещё всякие отладочные софт сбрасывает все переммные окружение в логи.
В идеале первым делом внутри созданного окружения нужно эти переменные обнулять, чтобы они дальше не растекались, но это не панацея и даже не всегда возможно.virtual_hack2root
14.01.2019 18:59Конечно я использую изляцию Docker-a, например, eсли использовать, к примеру Google Cloud Computing + Docker, то очень быстно выяснится, что
1) вся ВМ, все диски, все свапы — шифруются,
2) при использовании Docker-a внутри Google Cloud Computing, кроме всего прочего, удается решить проблему с разделением переменных окружения дочерними процессами, и самих данных в соседние процессы путем изоляции с помошью контейнеров.
3) при падении или компрометации отдельных компонент, взаимодействующих с внешним миром либо нет, тчень просто перезапустить или изолировать процесс и заменить его на другойSap_ru
14.01.2019 23:47+1А как решается утечка переменные внутри докера через дочерние процессы? Пременные же в любом случае наследуются, нет? И если у вас упадёт нечто дочернее и сбросит, например отладочные логи с перменными окружения, которые выйдут за пределы контейнера, то туда могут все ключи/пароли попасть и это может никто не заметить? Шифрование тут не поможет — это логи и они пути их неисповедимы, а критически важной ифнормации в них быть не должно.
Или какой-то софт внутри контейнера уязвимый, который может ключи элементарно получить и передать. Он бы этих ключей/паролей и не видел, а тут вот они — в переменных окружения.
Не понимаю, как именно гарантируется непердача переменный окружения за пределы контейнера в общем случае.
Или я что-то в принципиально не понимаю?gecube
15.01.2019 02:06В любом случае пароли хранятся в ОЗУ. Вопрос только в том сколько уровней абстракции нужно пройти, чтобы добраться до них. Короче — рутовый доступ к хост-машине с докером эквивалентен полному обладанию всеми секретами на ней.
А убежать из контейнера в хостовое окружение — ну, надо постараться (хоть и потенциально возможно, что при запуске привилегированных контейнеров, что при наличии уязвимостей в самом ядре ОС)
Сами переменные окружения это не так плохо, но можно лучше. Например, подготавливать файл с секретами при старте контейнера, потом его грохать. Нет окружения — нет проблем.
И ещё — а зачем нам вообще говорить о дочерних процессах? Если злоумышленник влез внутрь контейнера, то ок, это уже проблема. Независимо от наличия дочерних процессов.
Ещё могу вспомнить, что коллеги из Авито с подобной бякой боролись. И придумали свой велосипед, весьма неплохойSap_ru
17.01.2019 00:08+1Остаются логи. Т.к. перменные окружения любят класть в логи краш-дампы, т.к. масса проблем может быть вызвана именно ими.
Я как раз думал через переменные кличи передавать и решил не делать этого именно для контейнеров, т.к. там я не контролирую дальнейшее распространение окружения. Максимум — между двумя своми приложениями/скриптами, где я могу гарантированно переопредлить переменные среды сразу после вытаскивания чувтсвительной информации.gecube
17.01.2019 00:19Логи остаются проблемой независимо от переменных окружения, т.к. разработчики (в частности, джависты) любят многомегабайтные простыни стектрейсов, а там может быть что угодно… Поэтому маскирование чувствительной информации — is a must.
rraderio
17.01.2019 10:23А как вы маскируете чувствительную информацию? в приложении?
gecube
17.01.2019 10:46В приложухе — нет, не получится. Только если настроить несколько уровней logger'а.
Более удобно — сделать это на уровне хранилища логов (того же graylog), но это вычислительно дорого. Но можно просто вшивать в каждое сообщение с потенциально чувствительной информацией некий флаг (нужно доработать приложуху) и на входе в хранилище логов его фильтровать — тогда терпимо.
Т.е. итого — есть хранилище логов. Есть фильтрация на входе. Есть несколько потоков данных в интерфейсе: полный (для сотрудников ИБ и доверенных лиц) и очищенный (для всех остальных, кому нужен доступ).
Meklon
14.01.2019 12:01Кстати, подскажите, кто сталкивался с вариантами токенов для скриптов вживую? Мне рассказывали, но руками не трогал.
worldmind
14.01.2019 16:20ты про всякие oauth токены?
Meklon
14.01.2019 16:30Типа того. Ниже уже Hashicorp предложили с динамическими паролями. Смущает только то, что очень молодой проект. У них релиз 1.01 месяц назад был.
worldmind
14.01.2019 18:35С токенами тему чуток мутноватая (вроде считается секурнее, но я как-то не уверен, что сильно), я пару лет назад юзал гугловое апи чуток, в моём случае схема была такая (их там много вариантов) — юзер вводил свой логин/пароль в формочку гугла, а гугл в ответ возвращал приложению пару токенов, один быстропротухающий, а второй для обновления первого и в принципе приложение могло работать уже без участия юзера, но токены эти всё равно надо где-то хранить, если утечка одного первого токена ещё терпима, то если утекут оба, то считай утёк пароль, хотя токены вероятно чуток меньше доступов имеют.
enkaro
14.01.2019 21:41Вы описываете jwt (JSON Web Token).
Если утечет второй токен, сменится пароль и работающее взаимодействие (m2m или живая сессия) сломается.
Перестанут ходить данные и придется повторно себя аутентифицировать через пароль, ключ API и т.д.
mayorovp
15.01.2019 11:35+1Главный доступ, которого токены, как правило, не имеют — доступ к смене пароля. Даже если злоумышленник может делать от имени пользователя что угодно — он всё равно не может «угнать» аккаунт. Как только пользователь заметит неладное — он зайдёт в аккаунт через браузер и инвалидирует все токены.
По крайней мере, именно так эта схема должна работать.gecube
15.01.2019 16:51И еще идеально, когда токен привязывается к устройству (или ip, или любому другому критерию), чтобы для любого другого устройства (ip, другого критерия) нужно было 100% выписывать новый токен.
mayorovp
15.01.2019 17:03Привязка к ip будет означать постоянные разлогины при переключении с мобильной сети на домашний Wi-Fi. Другой критерий точно так же угоняется и подделывается.
gecube
15.01.2019 17:13Ну, расскажите, пожалуйста, нам как работает схема с токенами приложений в гугл gmail, например. Это реально интересный и полезный кейс.
Я — честно, не разбирался глубоко. Но могу предположить, что токены, которые мы видим при подключении приложении либо действительно могут быть переиспользованы, либо являются одноразовыми, и тогда на оконечном устройстве появляется что-то типа куки. И которая уже дальше и является ключом шифрования. Ну, может еще как-то текущее время завязано.
Всей этой криптографией и безопасностью интересовался давно, поэтому выпал из тренда.mayorovp
15.01.2019 17:20gmail я отдельно не исследовал, но при использовании токенов сейчас, как правило, используется простейшая схема — bearer token, токен «на предъявителя» без каких бы то ни было дополнительных криптозащит. Однако, у них ограничивается область возможного использования.
gecube
15.01.2019 17:34ОКей. Спасибо. Т.е. единственная защита от увода bearer token заключается в том, что
- best practice выписывать уникальный bearer token на каждого потребителя сервиса (что дает нам возможность их селективно блочить, т.е. отзывать bearer token)
- энтропия и длина bearer token должна быть достаточной, чтобы его нельзя было сбрутить (т.е. для операций с ним — защита на уровне протокола от сниффинга + защита на уровне сервера по rate limit запросов, включающих токен).
gecube
15.01.2019 09:17Hashicorp нормально делает. И хорошие (полезные и качественные) продукты. И энтерпрайз поддержка у них, если надо. Мои рекомендации.
Также хочу сказать, что без контекста номер версии ни о чем. Вспомним, как многие вендоры переходили с одной системы нумерации версий на другую. Как например, ОпенСусе прыгнули с 13 сразу на 42. Ваш К.О. или файрфокс аналогичный фортель выкинул…
immaculate
14.01.2019 12:07В проектах на Django использую библиотеку
django-environ
. При этом информация для соединения с базой данных берется либо из переменных окружения, либо из файла.env
. Например,DATABASE_URL=mysql://username:password@localhost/project
.
Для деплоя использую ansible c паролями, зашифрованными посредством Ansible Vault: в файлах ansible хранятся зашифрованные переменные, пароль шифрования хранится в отдельном файле на сервере CD. Таким образом, пароли в открытом виде никогда не попадают в репозиторий с исходным кодом.
Meklon
14.01.2019 13:10А для puppet/foreman/katello какое решение наиболее кошерно?
selivanov_pavel
15.01.2019 02:27Внизу в комментах git-crypt упоминали, но в отличие от ansible vault зашифрованные файлы лежат только в git-репозитории, а локально они остаются в открытом виде.
selivanov_pavel
15.01.2019 02:24Ещё в ansible можно использовать разные environments для разных наборов хостов. Для dev пароли будут в открытом виде user:qwerty, а для prod — зашифрованные vault.
nonname
14.01.2019 15:41Это будет работать пока у нас есть конкретные машины, в контейнерных средах это не работает. Лучше всего использовать что-то вроде Hashicorp Vault, хранить пароли там, а уже доставлять их в приложение можно разными способами, как обращением из кода приложения с сессионным ключом прямо в vault, так и внешними инструментами, доставляя пароль при деплое в те же env переменные или через secrets (k8s, rancher, etc..), ну или в систему управления конфигурациями, если она используется в CD. Плюсом такого подхода будет единое место хранения паролей.
arheops
14.01.2019 16:59Обясните мне, что компроментирует пароль в коде, если он действителен только для конкретного набора хостов?
Ну к тому же mysql
При взломе хоста имхо вас кейринг тоже не спасет.virtual_hack2root
14.01.2019 19:04во многих сложных системах, безусловно, есть не только внутренние хосты, видимые со специально оговоренных IP-адресов, но и внешние, либо динамическим списком IP-адресов, вот в таком случае, велик шанс, что злоумышленнику, получившему валидную пару логин-пароль удастя получить контроль над БД на уровне сервиса, предроставляющего доступ извне, путем подмены IP-адреса, либо MTM, либо несколькими другими способами, (0-Day, и т.д.)
enkaro
14.01.2019 21:46Для CredentialManager есть mimikatz, который доставляется на конечную машину, к примеру, через metasploit.
Получаются все нужные данные.
Дальше уже дело «прямоты» рук администратора mysql.
Прописал только конкретные IP, молодец, но есть варианты.
Прописал вместо IP %,… к без вариантов.
VGoudkov
14.01.2019 17:04Если копнуть чуть глубже — в полный, так сказать enterprise — то есть несколько крупных и дорогих программных продуктов, специализирующихся на управлении паролями. Работает для конечных
пользователейадминистраторов систем и для отдельных приложений, включая централизованную замену по расписанию во всём зоопарке, распечатку на бумагу для хранения в сейфе у CTO, логирование всего и вся и прочие приятности. Стоит денег, но закрывает многие требования и сценарии из области ИБ и прочих обязательных требований. В редких случаях спасает от серьёзных финансовых последствий.Meklon
14.01.2019 18:13Полностью согласен. Предложишь варианты?)
VGoudkov
16.01.2019 16:36По CyberArk я в своё время был сертифицированный инженер :) В принципе, такие вещи начинаются с Gartner Magic Quadrant (например тут), и выбираешь вендора. Потом смотришь функционал на сайтах (нужно что-то типа CLI / application-to-application password management). Потом к толстым системным интеграторам, которые у вендора на сайте заявлены как партнёры, за ценником и PoC (Proof Of Concept, он же пилот). Обычно такие штуки всё равно через партнёров продаются, так что напрямую скорее всего не получится.
TimsTims
14.01.2019 17:21только после входа пользователя в систему
Но ведь есть ещё другие скрипты, которые запускаются по расписанию на сервере. И если мы говорим про всякие powershell, то это Windows server, а значит там не будет автоматического логина на сервер, а значит скрипт который лежит в планировщике, или в сервисах не сможет получить доступ к хранилищу...
Meklon
14.01.2019 18:16+2Скрипт может работать под технологической учётной записью. И vault будет использоваться именно ее, а не живого админа.
virtual_hack2root
14.01.2019 19:09а если саму учетную запись спрятать в переменных окружения, то даже получив исходный код, злоумышленнику не удастся воспользоваться им для получения доступа к системе
TimsTims
15.01.2019 10:01Это понятно, что ТУЗ будет, но вы написали что сначала под этой ТУЗ надо авторизоваться("только после входа в систему"). Т.е. при каждом обновлении сервера и каждой перезагрузке нужно будет авторизоваться на сервере.
The_Kf
14.01.2019 19:15Для PowerShell на Windows есть и ещё варианты — можно шифровать пароль сертификатом (лежащим в стандартном хранилище сертификатов, разумеется) или просто аутентифицироваться прям этим сертом.
geisha
14.01.2019 20:11+1Спасибо, не думал, что всё так просто. Заменил b64decode на keyring в скриптике и он молча отработал. Вопрос: полное отсутствие функции получения списка паролей — это из-за требований совместимости, хитрая защита или просто так случилось?
Jek_Rock
14.01.2019 20:56Как вы прячете секреты из истории комманд в Windows и Linux? Например, если нужно консольным клиентом подключиться к базе.
Meklon
14.01.2019 21:15+1Системные варианты ввода пароля. В посте getpass описан. Для bash тоже есть аналогичный безопасный ввод. Надо выключить echo для команды с ключом -s:
#!/bin/bash # Read Password echo -n Password: read -s password echo # Run Command echo $password
В powershell будет что-то вроде:
$SecurePassword = Read-Host -Prompt "Enter password" -AsSecureString
nikoloza
15.01.2019 17:30Начните команду с пробела и он не будет писаться в лог.
Актуально для bash с HISTCONTROL=ignorespace
Gasoid
14.01.2019 23:49+1все переменные вынести в конфиги, конфиги генерить уже на хосте, пароли хранить отдельно в CI/Vault/Env
ну и cur.fetchall() очень плохо, а если там 1млн записей?
Meklon
14.01.2019 23:52ну и cur.fetchall() очень плохо, а если там 1млн записей?
SQL не моя сильная сторона, признаю. Не использую как-то… Это всего лишь пример)
fear86
15.01.2019 01:02Поднимайте все узлы в изолированной сети, монтируйте файловую систему в readonly с noexec, используйте ротацию паролей с небольшим ttl. И спите спокойно ))
ps: Всегда помните, что приложения открытые в мир по умолчанию уязвимы. И главный вопрос не «что делать если сломают?», а «что делать когда сломают?». Этот план должен быть составлен и проработан, для уменьшений деструктивных последствий атаки.
selivanov_pavel
15.01.2019 02:19Linux-овый keyring работает через PAM, и только если пользователь при входе вводил пароль, насколько я понимаю с участием этого самого пароля. Если используется какой-нибудь способ входа без пароля — то keyring остаётся закрытым. Так что на сервере неприменимо.
ИМХО всё чувствительное надо выносить в отдельный конфиги, которые раскладываются из ansible vault, harshicorp vault и всяких прочих AWS KMS.gecube
15.01.2019 09:19Т.е. скорее вопрос в том, что если нужно сетевое хранилище данных, то keyring не подойдёт (или к нему удаленно можно цепляться?)
selivanov_pavel
15.01.2019 09:44Удалённо цеплять тоже нельзя, но главное, что его не получится использовать для работающей в фоне службы на сервере. Он для десктопных приложений. По крайней мере в Linux, не знаю как насчёт Windows и MacOS.
Meklon
15.01.2019 10:08Почему нельзя? Запускаем скрипт от технологической учетки machine01. Делаем set_passwd. Все. Теперь в этой учетке есть пароль и можно таскать его скриптами через get_passwd.
selivanov_pavel
15.01.2019 10:32В системе хранится только солёный хеш пароля, в /etc/shadow для локальных пользователей. Получить сам пароль пользователя PAM модуль может только при вводе этого пароля пользователем при логине.
В этом и весь смысл keyring: не получится получить доступ к зашифрованным данным, даже если удалось получить доступ к файлам. Нужно получить ещё и пароль пользователя.Meklon
15.01.2019 10:59Твою мать( Спасибо. А неинтерактивно как это решить? В виде демонов/скриптов для m2m? Если без стороннего ПО.
selivanov_pavel
15.01.2019 11:21Как убрать пароли в открытом виде из исходников? Обычно это решается вынесением паролей в конфиг либо environment, и раскладыванием этого конфига или environment снаружи средствами CI, configuration management(ansible/puppet/...) или что там у вас есть. Ну и строгими разрешениями, чтобы прочитать этот файл мог только пользователь соответствующей службы, а не любой пользователь на хосте(неактуально для контейнеров).
Для ленивых — можно по каким-то признакам определять, работает приложение в dev или prod среде, и считывать соответствующий config.dev.yml либо config.prod.yml. Первый при этом не так страшно положить в исходники, а второй всё-же должен появляться на хосте в процессе деплоя, руками или автоматикой. А, ну и добавить config.prod.yml в .gitignore на всякий пожарный.
AlexPancho
15.01.2019 10:37мой способ не самый надежный, но довольно простой — хранить пароли в питон-файле, файл добавить в исключение гит (или что там у вас), импортировать в рабочий файл.
#Примерно так import nsfw user_pass = nsfw.userpass01
Естественно, так можно хранить целые словари логинов-паролей, и доставать значение по ключам.
KorP
С пол года как перешёл на использование keyring, пока претензий нет