Защита вашего API_KEY и почему это важно

  • 8 сентября, 07:10
  • 4572
  • 0

Вы оставляете ключи в машине на парковке? Если нет, то почему вы выставляете свои API_KEYs в своих проектах Github?

Развертывание приложений с использованием облачных сервисов является нормой, но сопровождается сложностями безопасности. Для облачных сервисов требуются учетные данные, часто в форме токенов API. Подлые хакеры ищут эти токены для использования в качестве вычислительных ресурсов для майнинга криптовалюты или используют их для доступа к конфиденциальным данным.

Защита вашего API_KEY и почему это важно

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

Основная проблема заключается в том, что исторически разработчики хранили api_keys в коде

Код ниже не так сложно найти,

# src/keys/api_key.js
SOME_SERVICE_API_KEY = '2es8-473t-43ef-a34d' # Don't tell anyone!

Многие разработчики постоянно выставляют свои ключи API в коде, затем они запускают репо и вуаля!

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

Я должен был разработать проект как задание, и одним из требований было использование сервисов «The Movie Database API». Способ сделать это - предоставить API_KEY при каждом вызове службы. В моем случае ключ не будет полностью скрыт при запуске приложения.

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

Добавьте API_KEYS с помощью веб-пакета

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

Я использовал веб-пакеты DefinePlugin, что позволило мне создать API_KEY как глобальную константу, которую можно настроить во время компиляции.

new webpack.DefinePlugin({
  // Definitions...
});

Это определение в моем файле webpack.config выглядит так:

module.exports = env => {
  ...    
  plugins: [
      new webpack.DefinePlugin({
        'process.env.apiKey': JSON.stringify((env && env.apiKey) || ''),
     }),
  ],

Обратите внимание, что настройка module.exports с функцией, вместо непосредственного присвоения объекта, важно. В противном случае вы не получите доступ к env переменной.

Давайте углубимся в файл конфигурации

Конфигурация должна быть в состоянии обслуживать приложение как в режиме разработки, так и в режиме производства. Конечно, если вы используете веб-пакет, он также включает в себя HMR (Hot Mode Reload).

Вот как приложение работает в режиме разработки:

TMDB_API_KEY=<yourTmdbApiKey>
npm run serve-dev  -- --env.apiKey=${TMDB_API_KEY}

И, вот в производственном режиме:

TMDB_API_KEY=<yourTmdbApiKey>
npm run build:webpack -- --env.apiKey=${TMDB_API_KEY} && \
 npm run serve-prod

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

В этом контексте это означает, что параметры после -- должны быть отправлены в команду serve-dev или же build:webpack в зависимости от сценария, который вы запускаете.

Я добавил следующий код в начало моего файла webpack.config, чтобы убедиться, что тот, кто запускает приложение, знает, что API_KEY необходим для запуска сценариев и загрузки приложения.

if (!env || !env.apiKey) {
    throw new Error(
      'You need to specify your tmdb api-key. You can do so by specifying ' +
        '--env.apiKey=<yourkey> in the command line. For example:\n' +
        '$ npm run serve-dev  -- --env.apiKey=<yourkey>\n' +
        ' or \n' +
        '$ npm run build-webpack -- --env.apiKey=<yourkey> && npm run serve-prod',
    );
  }

На данный момент у меня все готово в моем конфигурационном файле. Я импортирую этот модуль и возвращаю API_KEY, который я получаю после выполнения команд.

У меня есть следующий код в файле api_key.js, который находится там, где я использую сервис.

export function getApiKey(): string {
  if (!process.env.apiKey) {
    throw new Error(
      'You need to specify your tmdb api-key. You can do so by specifying ' +
        '--env.apiKey=<yourkey> in the command line. For example:\n' +
        '$ npm run serve-dev  -- --env.apiKey=<yourkey>',
    );
  }
  return process.env.apiKey;
}

И сценарии мой package.json выглядит так ...

"serve-dev": "webpack-dev-server --mode=development --config webpack.config.js",
"build:webpack": "webpack --mode=production -p --config webpack.config.js",
"serve-prod": "serve dist",
"test": "jasmine-ts --config=spec/support/jasmine.json",
"test-watch": "nodemon --ext ts --exec 'npm run test'",

Но что происходит с тестовыми сценариями?

Обычно нам не нужен API_KEYS для тестирования. Но в моем случае у меня есть некоторый код в тестах, который косвенно вызывает функцию, которая возвращает API_KEY.

Чтобы избежать использования правильного API_KEY, я добавил в babel.js этот код:

// Global variables needed for api_key.ts.
// The function getApiKey() is not really needed for the tests (we mock the
// access to tmdb), but it is executed as part of the instantiation of the
// Injector class.
process = process || {};
process.env = process.env || {};
process.env.apiKey = 'dummy';

Теперь просто запустите тестовый скрипт npm, не передавая apy_key:

npm run test

Теперь вы должны быть готовы к запуску приложения, не указывая в коде ваши api_keys.


0 комментариев
Сортировка:
Добавить комментарий

IT Новости

Смотреть все