Как сделать безопасное шифрование с помощью Jasypt?

#java #spring #spring-boot #encryption #jasypt

Вопрос:

На jasypt.org что касается вопроса «Могу ли я расшифровать зашифрованный пароль?«здесь написано http://www.jasypt.org/faq.html#does-jasypt-implement-algorithms : «Если вы зашифровали его с помощью метода переваривания сообщений, что именно то, что вы должны были сделать (с помощью реализации шифратора пароля, StandardStringDigester или аналогичного…), вы не можете«.

Должен сказать, что я пробовал по-разному, но мне кажется, что у меня всегда одна и та же проблема. Я не знаю, почему Jasypt позволяет каждому расшифровать исходное значение. Например, я могу легко зашифровать его, но также расшифровать с помощью команд mvn:

Пример шифрования и дешифрования с помощью jasypt:

зашифровать:

 mvn jasypt:encrypt-value -Djasypt.plugin.value="test" -Djasypt.encryptor.password="pass" -Djasypt.encryptor.algorithm="PBEWithMD5AndDES" -Djasypt.encryptor.key-obtention-iterations=1000 -Djasypt.encryptor.pool-size=1 -Djasypt.encryptor.provider-name="SunJCE" -Djasypt.encryptor.salt-generator-classname="org.jasypt.salt.RandomSaltGenerator" -Djasypt.encryptor.iv-generator-classname="org.jasypt.iv.NoIvGenerator" -Djasypt.encryptor.string-output-type="base64"
 

Как вы можете видеть, в первой команде я указываю значение «тест» и пароль «пропуск» для расшифровки.
Он генерирует: ENC(u7uKa3B9Xfey zZ46tOmag==)

И с этим я могу легко выполнить вторую команду, и я получу исходное значение, которое является «тестом».

расшифровать:

 mvn jasypt:decrypt-value -Djasypt.plugin.value="u7uKa3B9Xfey zZ46tOmag==" -Djasypt.encryptor.password="pass" -Djasypt.encryptor.algorithm="PBEWithMD5AndDES" -Djasypt.encryptor.key-obtention-iterations=1000 -Djasypt.encryptor.pool-size=1 -Djasypt.encryptor.provider-name="SunJCE" -Djasypt.encryptor.salt-generator-classname="org.jasypt.salt.RandomSaltGenerator" -Djasypt.encryptor.iv-generator-classname="org.jasypt.iv.NoIvGenerator" -Djasypt.encryptor.string-output-type="base64"
 

В моем файле .pom я определил это в части зависимостей:

 <dependency>
    <groupId>com.github.ulisesbocchio</groupId>
    <artifactId>jasypt-spring-boot</artifactId>
    <version>3.0.2</version>
</dependency>
 

а также это в части сборки (чтобы я мог выполнить jasypt через maven):

 <plugins>
    <plugin>
      <groupId>com.github.ulisesbocchio</groupId>
      <artifactId>jasypt-maven-plugin</artifactId>
      <version>3.0.2</version>
    </plugin>
<plugins>
 

Мое приложение yml выглядит так:

 jasypt:
    encryptor:
        password: pass
        algorithm: PBEWithMD5AndDES
        key-obtention-iterations: 1000
        pool-size: 1
        provider-name: SunJCE
        salt-generator-className: org.jasypt.salt.RandomSaltGenerator
        iv-generator-className: org.jasypt.iv.NoIvGenerator
        string-output-type: base64
        
spring:
  datasource:
    database-name: *****
    jdbc-url: *****
    username: *****
    password: ENC(u7uKa3B9Xfey zZ46tOmag==)
 

И все работает нормально (я пробовал это также с bean через java-код, это совершенно то же самое, просто другой стиль). Но почему я должен это делать и оставлять все как есть, зная, что хакер может, как и я, выполнить эту команду и получить реальную ценность:

Он может это сделать, и у него есть все, что ему нужно — он может прочитать как «u7uKa3B9Xfey zZ46tOmag==«, так и «передать» из моего кода: расшифровать:

 mvn jasypt:decrypt-value -Djasypt.plugin.value="u7uKa3B9Xfey zZ46tOmag==" -Djasypt.encryptor.password="pass" -Djasypt.encryptor.algorithm="PBEWithMD5AndDES" -Djasypt.encryptor.key-obtention-iterations=1000 -Djasypt.encryptor.pool-size=1 -Djasypt.encryptor.provider-name="SunJCE" -Djasypt.encryptor.salt-generator-classname="org.jasypt.salt.RandomSaltGenerator" -Djasypt.encryptor.iv-generator-classname="org.jasypt.iv.NoIvGenerator" -Djasypt.encryptor.string-output-type="base64"
 

Ему просто нужно прочитать этот код ENC(u7uKa3B9Xfey zZ46tOmag==) (который он может получить из файла yml и «передать» также из файла yml (он также может это сделать). И вот оно, он может вернуть первоначальную стоимость. Я не вижу в этом никакой безопасности. Хакеру нужно только знать, как выполнить команду mvn decrypt (мне удалось сделать это здесь, в этом примере, почему кому-то тоже не удалось бы это сделать), и это в основном то же самое, что и шифрование.

Кто-то может возразить: «Ну, вы можете передать свой пароль («передать») через переменную среды». На меня это не действует. Потому что оба файла для Gitlab и Dockerfile у меня есть в проекте, и если я установлю там эти переменные, хакер все равно сможет прочитать их, и они получат фактическое значение за считанные секунды. Они привязаны к моему проекту. Кроме того, предоставление реальных паролей, таких как переменные среды, в таких системах, как Gitlab или Kubernetes, кажется мне очень рискованным. Хакер, если он очень продвинут, может также прочитать эти значения. Так зачем же их разоблачать? И, похоже, это единственное решение от Jasypt, чтобы установить переменные, такие как APP_ENCRYPTION_PASSWORD.

Мой вопрос в том, можете ли вы каким-то образом отключить расшифровку Jasypt, чтобы не возвращать фактическое значение, чтобы хакер также не мог добраться до него? Мне кажется, это самый безопасный вариант. Или какое-то аналогичное решение для решения моей проблемы? Приведите пример, если можете, пожалуйста. Было бы хорошо, если бы Jasypt мог каким-то образом генерировать пароль на лету, точно так же, как он генерирует соль, но как. Я знаю, что тогда человек должен динамически заполнять файл yml, а это невозможно. Я действительно не понимаю, как это с Jasypt безопасно, если мне нужен только пароль и зашифрованное значение для расшифровки исходного значения. Оба этих хакера могут читать исходный код, и, на мой взгляд, это кажется очень плохой безопасностью. И затем, какова цель маскировки passoword базы данных в файле yml. Если все можно распаковать за считанные секунды. Мне это кажется очень слабой защитой. Пожалуйста, сообщите мне, как я могу сделать его более безопасным, чем сейчас.

Ответ №1:

«Если вы зашифровали его с помощью метода переваривания сообщений,… ты не можешь».

Это неудачная формулировка. Вы либо шифруете данные (обратимые), либо хэшируете (не поддающиеся преобразованию).

На самом деле есть много таких вопросов, поэтому просто найдите его. Если у вас есть секрет для службы (например, учетные данные БД, ключ API), вы можете зашифровать их, но вам также нужно где-то иметь ключ.

ну, вы можете передать свой пароль («пройти») через переменную окружения

Это самый простой способ отделить секреты от кода. Вы должны решить, в чем заключается угроза, от чего вы хотите защититься и как. Если вы ограничиваете возможность утечки секретов с исходным кодом, может помочь использование переменных среды или параметров развертывания.

Кроме того, предоставление реальных паролей, таких как переменные среды, в таких системах, как Gitlab или Kubernetes, кажется мне очень рискованным.

если кто — то получает доступ к вашему компьютеру, это уже не ваш компьютер. Используя параметр kubernetes secrets или Ansible vault, pipeline, … это может помочь отделить секреты от вашей кодовой базы.

Хакер, если он очень продвинут, может также прочитать эти значения.

если кто-то может выдать себя за вас или приложение, вы ничего не сможете с этим поделать. Вот почему вам нужно предотвратить это (минимум привилегий, безопасность на всех уровнях, ..)

Мой вопрос в том, можете ли вы каким-то образом отключить расшифровку Jasypt, чтобы не возвращать фактическое значение, чтобы хакер также не мог добраться до него?

.. и тогда ваше приложение также не получит его обратно, и приложение не сможет получить доступ к базе данных или другим службам.

Есть варианты аутентификации другим способом (например, Kerberos), но я лично стараюсь избегать этого, так как настроить и устранить неполадки непросто. А затем мы остаемся с паролями и ключами, хранящимися где-то в среде или в конвейере развертывания.