Как зашифровать пароль в скрипте
Прячем JavaScript-код на фронтенде от посторонних
Авторизуйтесь
Прячем JavaScript-код на фронтенде от посторонних
Рассказывает веб-разработчик Денис Лисогорский
Давайте представим ситуацию, когда вы и ваша команда пишете интересный и сложный код на JavaScript. Причём этот код в кратчайшие сроки нужно использовать в проекте. Если его функциональность действительно уникальна, то в процессе разработки и у вас, и у членов команды вполне резонно возникнет вопрос: «Как защитить код от копирования?».
Как защитить код: веб-сокеты, крипторы и обфускация
Разумеется, все мы прекрасно понимаем, что JavaScript выполняется на стороне браузера. И любой зашифрованный код всегда можно расшифровать, если знать принципы работы браузера. Поэтому можно попробовать лишь затруднить понимание данного кода, а это, в свою очередь, очень сильно помешает злоумышленнику модифицировать его под свои нужды.
Итак, есть несколько вариантов защиты кода:
Крипторы приводят код в нечитаемый вид, используя, как правило, base64 (что неизбежно приводит к увеличению объёма кода примерно на 30%). Затем к полученному результату прибавляется так называемая «соль» — набор символов, который при разборе кода функцией-дешифровщиком используется в качестве ключа. Ну а потом вся строка кода обычно выполняется через eval(). Проблема крипторов в том, что если понять принцип их работы, отсечь «соль» и декодировать, то сразу становится доступен весь код в его исходном виде.
Обфускаторы же изменяют сам код, вставляя между операторами нечитаемые символы, меняя имена переменных и функций на набор визуально непонятных символов. При этом объём кода также сильно увеличивается из-за вставки дополнительного псевдокода, а также замены символов на hex, когда любые символы переводятся в их hex-значения (например, латинская буква ‘e’ может быть записана как ‘\x65’, причём это прекрасно интерпретируется любым браузером). Можете посмотреть, как работает перевод в hex через любой сервис Text To Hex, например на Crypt Online.
Также есть всем известный Closure Compiler от Google, который кроме минимизации анализирует JavaScript-код, удаляет мёртвый код, переписывает и сводит к минимуму то, что осталось. Он также проверяет синтаксис, ссылки на переменные и типы и предупреждает об общих ошибках JavaScript. Имеет хорошо документированный API.
Кроме предложенных методов можно сделать следующее:
Всё это, разумеется, не станет стопроцентной защитой. Тем не менее чем сложнее процесс дешифровки, тем больше шансов, что после множества неудачных попыток любители копировать чужой код оставят ваш сайт в покое.
Зашифровка кода на примере JavaScript-калькулятора
Не так давно я разработал JavaScript-калькулятор для расчёта стоимости услуг, с большим количеством взаимосвязанных параметров. Руководство поставило задачу защитить данный скрипт от копирования, чтобы конкуренты не смогли использовать его на своих сайтах. Искал различные решения, ничего подходящего не нашёл, поэтому начал писать собственное. Представляю его ниже.
Обращаю ваше внимание на то, что любой код можно расшифровать, просто для этого нужно время. Поэтому данное решение, разумеется, не идеально. Тем не менее, чтобы его раскрыть, требуется время, внимательность и усидчивость. И это может оттолкнуть ваших конкурентов от идеи скопировать ваш скрипт. Большинство из них после нескольких неудачных попыток просто будут искать аналог похожего скрипта на других ресурсах.
По итогам работ в браузере вы увидите нечто такое:
При этом все зашифрованные скрипты будут работать корректно. Опытный взгляд программиста сразу визуально определит кодирование через base64. Но при попытке расшифровать строку любым base64 декодером, будет ошибка. Если вставить скрипт в alert (такой метод также рекомендуют на форумах для дешифровки кода), то результат также будет нулевым.
При этом никто ведь не знает, что здесь зашифрован именно скрипт. Это может оказаться какой-то параметр, текст или изображение. Через base64 можно зашифровать всё что угодно.
На этом месте многие закончат попытки расшифровки и оставят ваш сайт в покое.
Рассмотрим алгоритм подробнее.
Как защитить JavaScript от копирования на своём сайте
Первым делом указываем в футере сайта путь на скрипт и тут же кодируем его:
Добавление строки ‘K’ (это может быть любая латинская буква или комбинация букв или цифр) защищает нас от того, что желающий скопировать ваш скрипт расшифрует его с помощью alert() или онлайн-дешифратора. Ведь с дополнительными символами скрипт не будет работоспособен.
Затем где-то дальше в коде вызываем скрипт:
Пусть этот скрипт вызывается отдельно, подальше от других скриптов и ссылок на скрипты.
Далее где-то в файле с общими скриптами сайта, отдельно от других скриптов, вставляем вызов функций дешифровки. Вставлять можно независимо от других функций и библиотек.
Разбираем подробно что здесь происходит.
[] (это равно 1 в зашифрованном виде), которая извлекает из s строку начиная с первого символа и до конца. Следовательно, если мы в PHP-коде в качестве строки прибавляли более одного символа, скажем три, то нам нужно будет в функции substring() указать 2+(-
Пример замены цифр через побитовый оператор
Попробуйте ввести это в консоли браузера и вы увидите, что на самом деле делает эта функция. Например, вы увидите:
Вы уже догадались, что нужно сделать? 🙂 Выполните в консоли браузера и вы увидите:
Здесь, думаю, уже объяснять ничего не надо. Все мы знаем, что функция eval() выполняет скрипт, полученный из строки. «Плохая практика», как сказали бы многие, для обычного кода, но в нашем случае это безопасная и нужная функция для реализации нашей идеи. К тому же напрямую к этой функции пользователь не сможет получить доступ.
Наверное, вы задались вопросом, а каким же образом функции зашифрованы в наборе символов? Очень просто: набор символов — это текст, преобразованный в шестнадцатеричную систему счисления. Т.е. это текст в формате hex (hexadecimal), в котором можно зашифровать любые символы.
Таким образом, наша расшифрованная функция выглядит так (специально разбил по строчкам, чтобы было наглядно):
Всё будет работать как и раньше, но собьёт с толку нехороших копипастеров.
За материал благодарим нашего подписчика Дениса Лисогорского
Кодирование пароля с защитой Spring
Вступление
Кодирование пароля-это процесс, при котором пароль преобразуется из буквального текстового формата в нечитаемую по-человечески последовательность символов. Если все сделано правильно, очень трудно вернуться к исходному паролю, и поэтому это помогает защитить учетные данные пользователя и предотвратить несанкционированный доступ к веб-сайту.
Тем не менее, кодирование паролей является очень важным аспектом каждого приложения, и к нему следует относиться серьезно как к одному из основных шагов, которые мы предпринимаем для защиты личной информации и данных пользователя приложения.
Устаревшие Механизмы Безопасности
Буквальные значения
В не столь отдаленном прошлом пароли хранились в буквальном текстовом формате в базах данных без какого-либо кодирования или хэширования. Поскольку базы данных нуждаются в аутентификации, которой не было ни у кого, кроме администраторов и приложения, это считалось безопасным.
Поскольку пароли хранились прямо в текстовом формате, этого было вполне достаточно, чтобы они могли получить все пароли и сразу же их использовать.
Шифрование
Шифрование является более безопасной альтернативой и первым шагом на пути к безопасности паролей. Шифрование пароля зависит от двух вещей:
Один этот факт является ответственностью такого подхода. Поскольку ключи часто хранились на одном сервере, эти ключи часто попадали не в те руки, которые теперь имели возможность расшифровывать пароли.
Перемешивание
Чтобы бороться с этими атаками, разработчикам пришлось придумать способ защиты паролей в базе данных таким образом, чтобы их невозможно было расшифровать.
Однако эти стратегии не остались эффективными, так как злоумышленники начали хранить известные хэши с известными паролями и паролями, полученными в результате крупных утечек в социальных сетях.
Самый популярный из них – RockYou.txt содержит более 14 миллионов паролей для более чем 30 миллионов учетных записей. Забавно, но почти 300 000 из них использовали пароль “123456”.
Это все еще популярный подход, и многие приложения по-прежнему просто хэшируют пароли, используя хорошо известные функции хэширования.
Засолка
Чтобы бороться с появлением радужных таблиц, разработчики начали добавлять случайную последовательность символов в начало хэшированных паролей.
Хотя это не полностью изменило игру, это, по крайней мере, замедлило атакующих, поскольку они не могли найти хэшированные версии паролей в общедоступных таблицах rainbow. Поэтому, если бы у вас был общий пароль, например “123456”, соль не позволила бы сразу идентифицировать ваш пароль, так как он был изменен перед хэшированием.
Медленное Перемешивание
Злоумышленники могут использовать практически любую функцию, о которой вы можете подумать. В предыдущих случаях они использовали скорость хеширования, что даже приводило к хешированию методом перебора и сравнению паролей.
Кодировщики Паролей
Spring Security предоставляет несколько реализаций кодирования паролей на выбор. У каждого из них есть свои преимущества и недостатки, и разработчик может выбрать, какой из них использовать, в зависимости от требований аутентификации своего приложения.
BCryptPasswordEncoder
BCryptPasswordEncoder использует алгоритм BCrypt для хэширования паролей, который был описан ранее.
Вот как выглядит хэшированный пароль:
Несколько вещей, которые следует иметь в виду в отношении хэшированного пароля, это:
Кодер Pbkdf2PasswordEncoder
Pbkdf2PasswordEncoder использует алгоритм PBKDF2 для хэширования паролей.
Он имеет три необязательных аргумента:
Секрет-это тип объекта java.lang.CharSequence и когда разработчик предоставляет его конструктору, закодированный пароль будет содержать секрет.
Вот как выглядит хэшированный пароль:
Здесь важно отметить длину хэша, на которую мы можем напрямую влиять.
Мы можем определить короткий хэш (5):
Или очень длинный (256):
Чем длиннее вывод, тем безопаснее пароль, верно?
Да, но, пожалуйста, имейте в виду – это безопаснее до определенного момента, после чего это просто становится излишеством. Обычно нет необходимости хэшировать дальше 2 128 поскольку это уже хэш, который практически невозможно взломать с помощью современных технологий и вычислительной мощности.
Шифратор паролей SCrypt
Шифратор паролей SCrypt использует алгоритм шифрования для хэширования паролей.
Выводом его конструктора является производный ключ, который на самом деле является ключом на основе пароля, используемым для хранения в базе данных. Вызов конструктора имеет необязательные аргументы:
Пожалуйста, имейте в виду, что кодировщик паролей SCrypt редко используется в производстве. Отчасти это связано с тем, что изначально он не был предназначен для хранения паролей.
Хотя это спорно, дать “Почему я не рекомендую сценарий” чтение может помочь вам сделать выбор.
Вот как выглядит хэшированный пароль:
Делегирование Кодировщика паролей
В индустрии программного обеспечения многие приложения все еще используют старые кодеры паролей. Некоторые из них нелегко перенести на более новые кодеры и технологии, хотя с течением времени требуются новые технологии и подходы.
Реализация Делегирования кодировщика паролей решает многие проблемы, включая ту, которую мы обсуждали выше:
Git Essentials
Ознакомьтесь с этим практическим руководством по изучению Git, содержащим лучшие практики и принятые в отрасли стандарты. Прекратите гуглить команды Git и на самом деле изучите это!
В вызове конструктора мы передаем два аргумента:
Каждая строка списка содержит префикс типа кодера в строковом формате и соответствующий ему кодер.
Вот как выглядит хэшированный пароль:
Во время аутентификации предоставленный пользователем пароль, как обычно, сопоставляется с хэшем.
Демонстрационное приложение
Теперь, когда со всем этим покончено, давайте продолжим и создадим простое демонстрационное приложение, которое использует BCryptPasswordEncoder для хэширования пароля при регистрации. Тот же процесс будет выполняться для всех других кодеров, как показано выше.
Зависимости
Как и во всех проектах Spring и Spring Boot, давайте начнем с необходимых зависимостей:
Позаботившись о наших зависимостях, давайте продолжим и протестируем наш кодировщик по выбору:
Запуск этого фрагмента кода приведет к:
Конфигурация на основе XML
Конфигурация на основе Java
Мы также можем настроить кодировщик паролей в файле конфигурации на основе Java:
Модель пользователя
После завершения всей настройки приложения мы можем продолжить и определить Пользователя модель:
Сама модель довольно проста и содержит некоторую основную информацию, необходимую для ее сохранения в базе данных.
Уровень обслуживания
Весь уровень обслуживания обрабатывается UserDetailsManager для краткости и ясности. Для этой демонстрации нет необходимости определять пользовательский уровень обслуживания.
Это позволяет очень легко сохранять, обновлять и удалять пользователей для целей этой демонстрации, хотя я лично рекомендую определить уровень пользовательского сервиса в ваших приложениях.
Контроллер
Контроллер выполняет две задачи – позволяет пользователям регистрироваться и позволяет им впоследствии входить в систему:
После получения запроса POST мы получаем информацию Пользователя и хэшируем пароль с помощью нашего кодера.
После этого мы просто предоставляем полномочия нашему зарегистрированному пользователю и объединяем имя пользователя, хэшированный пароль и полномочия в один объект, используя UserDetails – Опять же, для краткости и простоты демонстрационного приложения.
Смотреть
Теперь, чтобы завершить все, нам нужно несколько простых представлений, чтобы сделать наше приложение функциональным:
Индекс
Зарегистрировать
Тестирование приложения
Давайте продолжим и запустим наше приложение, чтобы проверить, нормально ли оно работает.
Поскольку мы не вошли в систему, страница индекса просит нас либо зарегистрироваться, либо войти в систему:
При перенаправлении на страницу регистрации мы можем ввести нашу информацию:
Все прошло гладко, и нам будет предложено перейти на страницу успешной регистрации:
Сделав шаг назад, в базе данных мы можем заметить нового пользователя с хэшированным паролем:
Теперь мы можем вернуться в приложение и попытаться войти в систему:
После ввода правильных учетных данных нас снова встречает наша страница индекса, но на этот раз с другим сообщением:
Вывод
Реализации популярных алгоритмов хеширования Spring Security работают как заклинание, при условии, что пользователь не выбирает действительно плохой пароль. Мы обсудили необходимость кодирования паролей, некоторые устаревшие подходы к защите паролей от потенциальных злоумышленников и реализации, которые мы можем использовать для этого в более безопасном и современном подходе.
В конце концов, мы создали демонстрационное приложение, чтобы показать BCryptPasswordEncoder в использовании.
Безопасный ввод и сохранение зашифрованных паролей в конфигах Linux: пишем скрипт на Python
Как вывести свою систему на новый уровень безопасности с модулями python-gnupg и getpass4.
Изображение : freeGraphicToday, via Pixabay. CC0.
В условиях растущих требований к безопасности создание и хранение паролей может вызвать вопросы не только для пользователей, но и у разработчиков и системных администраторов. Специалисты и другие осведомлённые люди знают, что пароли нужно хранить в зашифрованном виде. Уже на этапе ввода символы пароля нужно скрывать от любых глаз (даже от того человека, который его вводит). Всегда ли мы можем выполнить хотя бы эти требования?
Я единственный пользователь своего ноутбука, а на его борту крутится ОС семейства Linux. Поэтому меня не беспокоят пользователи, которые могут случайно или неслучайно посмотреть мои конфигурационные файлы, работая на этом же компьютере. Я решил заморочиться и повысить безопасность своего личного ноутбука, и на то есть свои причины. Да, я шифрую свой домашний каталог, но как только вхожу в систему, любой пароль, хранящийся в виде простого текста в файле конфигурации, потенциально может быть уязвим для чересчур любопытных глаз.
К тому же, я использую почтовый клиент Mutt. Он позволяет мне читать и составлять электронные письма прямо в Linux-терминале. Мне удобно, мне нравится. Правда, ему нужно, чтобы я хранил пароль в файле конфигурации (.mutt), либо всё время вводил пароль в интерактивном режиме. Поэтому я ограничил права доступа к моему конфигурационному файлу Mutt, чтобы его мог видеть только я.
Но есть ещё один важный момент: я периодически пишу технические статьи, составляю туториалы, помогаю людям в сообществе и публикую много своего кода в общедоступных репозиториях, публикую скриншоты своего экрана, часто показываю что-то на примере своей рабочей системы. Если по недосмотру меня угораздит засветить в Интернете (или где-то ещё) данные (и в том числе пароли) из моих конфигурационных файлов, это бросит неприятную тень на мою репутацию и безопасность. Так что надо подстраховаться.
Ну и, если вдруг злоумышленник завладеет моим ноутбуком или каким-то другим образом получит доступ в систему, он не сможет получить мой пароль без боя, просто запустив cat для просмотра логов и конфигов.
Поиск решения задачи
Я решил, что лучший способ защитить мой пароль в Mutt — ввести пароль с клавиатуры, сохранить его в зашифрованном файле GPG, написать на Python скрипт расшифровки для моего GPG-пароля, ну и заодно обеспечить передачу пароля Mutt в скрипт offlineimap, который я использую для локальной синхронизации моего ноутбука с почтовым сервером.
Из подзаголовка статьи ясно, что я буду использовать модули python-gnupg и getpass. Модуль Python python-gnupg — это обёртка для инструмента шифрования gpg. Учтите, python-gnupg не следует путать с модулем под названием gnupg. GnuPG (GPG) — это утилита шифрования для Linux, и я использую её с 2009 года или около того. С ней я чувствую себя комфортно и верю в её безопасность.
Получить пользовательский ввод с помощью Python довольно просто. Вы вызываете input, и всё, что введёт пользователь сохраняется в переменной:
И в этом случае есть одна громадная проблема: когда я ввожу пароль в терминале, всё, что я набираю, видно всем, кто смотрит через моё плечо или просматривает историю моего терминала:
Написание скрипта с python-gnupg и getpass
Как это часто бывает, ничего самому писать не надо, потому что уже существует модуль Python, который позволяет решить проблему. Это модуль getpass4. С точки зрения пользователя он ведёт себя точно так же, как любое стандартное приглашение к вводу, за исключением того, что не отображает введённые символы.
Установим оба модуля с помощью pip:
У меня получился вот такой скрипт для создания пароля с невидимым вводом и расшифровкой:
Сохраните файл как password_prompt.py, если хотите попробовать скрипт у себя. Если вместе с ним вы хотите использовать offlineimap, укажите в конфигурационном файле .offlineimaprc имя и путь к скрипту с паролем (у меня это
/.mutt/password_prompt.py). Правда, там нужно сделать ещё кое-что, но об этом позже.
Тестирование скрипта с gpg
Надеюсь, у вас уже установлен gpg, так как сейчас мы будем создавать зашифрованный файл пароля и тестировать скрипт.
Запускаем созданный ранее скрипт:
Ура! При вводе ничего не отображается, но если вы правильно введёте пароль (нужно ввести hello world), на следующей строке вы увидите тестовое сообщение «hello world». Оно же и является паролем, полученным в результате расшифровки файла
/.mutt/pass.gpg. Значит, скрипт работает правильно.
Интеграция с offlineimap
Сначала добавьте строку, ссылающуюся на файл нашего скрипта:
Теперь вместо пароля в строке с remotepasseval после знака «=» вызовите функцию get_api_pass(), которая живёт в скрипте password_prompt.py:
Всё! Теперь никто не сможет прочитать пароль из вашего конфигурационного файла!
Безопасность даёт свободу
Иногда кажется, что у меня паранойя: я много думаю о тонкостях обеспечения безопасности на моём личном компьютере. Действительно ли SSH конфиг должен иметь разрешения chmod 600? Действительно ли имеет значение, что пароль электронной почты находится в конфигурационном файле, спрятанном в скрытой папке, которая называется, как ни странно, .mutt? Хотя написать подобный скрипт на Python можно и для других конфигурационных файлов.
Зная, что в моих файлах конфигурации отсутствуют незашифрованные конфиденциальные данные, мне намного проще публиковать файлы в общедоступных репозиториях Git, копировать и вставлять сниппеты на форумах и делиться своими знаниями в форме актуальных, рабочих файлов конфигурации. С этой точки зрения, повышение уровня безопасности облегчило мне жизнь. А с таким количеством Python-модулей на все случаи жизни, сделать это было достаточно легко.
Аренда облачного сервера с быстрыми NVMе-дисками и посуточной оплатой у хостинга Маклауд.
Защита и шифрование паролей в скриптах PowerShell
Администраторы часто при написании сценариев автоматизации на PowerShell сохраняют пароли непосредственно в теле PoSh скрипта. Как вы понимаете, это крайне небезопасно при использовании в продуктивной среде, т.к. пароль в открытом виде могут увидеть другие пользователи сервера или администраторы. Поэтому желательно использовать более безопасный метод использования паролей в скриптах PowerShell, или шифровать пароли, если нельзя пользоваться интерактивным вводом.
Безопасно можно запросить от пользователя ввести пароль в скрипте интерактивно с помощью командлета Get-Credential. Например, запросим имя и пароль пользователя и сохраним его в объекте типа PSCredential:
При обращении к свойствам переменной можно узнать имя ползователя, который был указан.
Но при попытке вывести пароль, вернется текст System.Security.SecureString, т.к. пароль теперь хранится в виде SecureString.
Также для запроса пароля пользователя можно использовать команлет Read-Host с атрибутом AsSecureString:
$pass = Read-Host «Введите пароль» –AsSecureString
В рассмотренных выше способах использования пароля в скриптах PowerShell предполагался интерактивный ввод пароля при выполнении скрипта. Но этот способ не подойдет для различных сценариев, запускаемых автоматически или через планировщик.
В этом случае удобнее зашифровать данные учетной записи (имя и пароль) и сохранить их в зашифрованном виде в текстовый файл на диске или использовать непосредственно в скрипте.
Итак, с помощью комадлета ConvertFrom-SecureString можно преобразовать пароль из формата SecureString в шифрованную строку (шифрование выполняется с помощью Windows Data Protection API — DPAPI). Вы можете вывести шифрованный пароль на экран или сохранить в файл:
$Cred.Password| ConvertFrom-SecureString | Set-Content c:\ps\passfile.txt
Чтобы использовать зашифрованный пароль из файла нужно выполнить обратное преобразование в формат Securestring с помощью командлета ConvertTo-SecureString:
Таким образом, если скрипт будет запускаться под другим (сервисным) аккаунтом или на другом компьютере, необходимо использовать другой механизм шифрования, отдичный от DPAPI. Внешний ключ шифрования можно указать с помощью параметров –Key или –SecureKey.
Например, вы можете с помощью PowerShell сгенерировать 256 битный AES ключ, который можно использовать для расшифровки файла. Сохраним ключ в текстовый файл password_aes.key.
$AESKey = New-Object Byte[] 32
[Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($AESKey)
$AESKey | out-file C:\ps\password_aes.key
Теперь можно сохранить пароль в файл с помощью данного ключа:
Таким образом у нас получилось два файла: файл с зашифрованным паролем (passfile.txt) и файл с ключом шифрования (password_aes.key).
Их можно перенести на другой компьютер и попытаться из PowerShell получить пароль из файла (можно разместить файл ключа в сетевом каталоге)
Если не хочется заморачивать с отдельным файлом с AES ключом, можно зашить ключ шифрования прямо в скрипт. В этом случае вместо ключа в обоих случая нужно использовать
Как вы видите пароль не пустой, значит он был успешно расшифрован и может быть использован на других компьютерах.
И напоследок, самый печальный момент. Пароль из объекта PSCredential в открытом виде вытаскивается очень просто:
Можно извлечь пароль в текстовом виде и из SecureString:
Как вы понимаете, именно поэтому нежелательно сохранять пароли привилегированных учетных записей, таких как Domain Admins где бы то ни было кроме DC.