Плохая практика, которую мы часто делаем как разработчики бэкенда, — это оставлять свои секреты в коде.

80% кражи данных происходит из частного или общедоступного исходного кода, раскрывающего секреты в коде.

Когда мы говорим о секретах, мы сосредотачиваемся на любой конфиденциальной информации. Например, у нас есть ключи шифрования, соли для хеширования паролей, токены доступа, ключи API…

Как хорошие разработчики, мы должны осознавать, что мы подвергаем себя огромному риску, напрямую раскрывая эти различные секреты в коде, либо внутри нашей компании, либо на платформах управления версиями, таких как GitHub, GitLab или Bitbucket.

Если злоумышленник наткнется на эти секреты, он может использовать их для взлома и кражи данных.

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

Вот пример кода, который не должен воспроизводиться в ваших проектах:

public static void main(String[] args) {
    private static final String MY_SECRET = "u8OFvRDiJT241PGiwldxpW7X79bjf7h9";
    System.out.println(MY_SECRET);
}

Какую практику лучше всего применить?

Ну, есть много способов сделать это. Самый распространенный способ, который мы рассмотрим в этой статье, — это решение экстернализации секретов в неотслеживаемых файлах.

В частности, мы будем:

  • Создадим файл, в который будем складывать наши секреты
  • Мы добавим этот файл в .gitignore, чтобы не отследить его и не поддаться искушению отправить его на сервер git.
  • Мы создадим пример файла, подобный тому, который был создан ранее, содержащий нереальную или тестовую информацию, чтобы те, кому придется сотрудничать с нами в коде, имели представление о секретах, необходимых для работы программы.

Итак, давайте посмотрим на пример того, как выполнить этот дизайн разделения сначала с помощью NodeJS, а затем с помощью SpringBoot.

NodeJS: знаменитый файл .env

С помощью библиотеки dotenv мы можем создать файл .env в корне нашего проекта и поместить туда наши секреты. Все эти примеры взяты из официальной документации NodeJS, доступной по адресу: https://nodejs.dev/en/learn/how-to-read-environment-variables-from-nodejs/

# .env file
USER_ID="239482"
USER_KEY="foobar"
NODE_ENV="development"
# app.js file

require('dotenv').config();

process.env.USER_ID; // "239482"
process.env.USER_KEY; // "foobar"
process.env.NODE_ENV; // "development"

Мы создадим файл .env.example, чтобы включить неверную информацию.

# .env.exemple file
USER_ID="fakeData"
USER_KEY="fakefoobar"
NODE_ENV="development"

Таким образом, мы будем отслеживать файл .env.example, но не файл .env, содержащий информацию, которой мы не знаем. хочу раскрыть.

Когда разработчик клонирует репозиторий кода, он меняет .env.example на .env и помещает информацию для развития или местной среды.

С SpringBoot это также легко сделать: файлы application.properties

Мы можем создать файл application-dev.properties для среды разработки или файл application-local.properties для локальная среда, которую мы можем отслеживать с помощью Git. Но, например, файл application-prod.properties отслеживать не следует.

# application.properties file

spring.profiles.active=dev

spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix
# application-dev.properties or application-local.propertiesfile

server.port=8090
spring.datasource.username=username
spring.datasource.password=password

При такой структуре любой разработчик, желающий внести свой вклад, редактирует application-dev.properties или application-local.properties. файл в соответствии с его потребностями.

Чтобы извлечь информацию, записанную в этих файлах, в нашем коде, мы можем использовать аннотации или внедрить объект Environment.

@Value("${spring.datasource.username}")
private String userBucketPath; // username
import org.springframework.core.env.Environment;

class TestingEnvironnement {

 @Autowired
 private Environment env;
 
 public void testingEnv() {
     String username= env.getProperty("spring.datasource.username");
 }
}

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

Заключение

Никогда не раскрывайте ключи и различную конфиденциальную информацию в коде. Это очень опасно. Вместо этого мы должны реализовать решения, чтобы скрыть их как можно больше. Среди этих решений различные фреймворки, которые мы используем, уже предлагают достаточно убедительные подходы. Поэтому мы должны использовать их как можно больше.

Если вам интересна эта тема, вы также можете взглянуть на менеджер секретов ggshield и aws.

Спасибо.