Стратегия сохранения секретной информации, такой как ключи API, от контроля версий?

217

Я работаю над веб-сайтом, который позволит пользователям входить в систему с использованием учетных данных OAuth, таких как Twitter, Google и т. Д. Для этого мне нужно зарегистрироваться у этих различных провайдеров и получить суперсекретный ключ API, который у меня есть. защищать залогами от различных частей тела. Если мой ключ будет взломан, часть будет вырвана.

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

Поскольку я дешевый ублюдок, я бы предпочел использовать бесплатные сервисы контроля версий, такие как TFS в облаке или GitHub. Это оставляет меня с небольшой загадкой:

Как я могу сохранить свое тело нетронутым, когда мои ключи API находятся в моем коде, и мой код доступен в общедоступном хранилище?

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

  • Я мог бы удалить всю личную информацию из кода и отредактировать ее после развертывания. Это было бы очень трудно реализовать (я не буду подробно описывать многие способы), и это не вариант.
  • Я мог бы зашифровать это. Но, как я должен расшифровать, любой, у кого есть источник, может понять, как это сделать. Бессмысленно.
  • Я мог бы заплатить за частный контроль источника. LOL J / K тратить деньги? Пожалуйста.
  • Я мог бы использовать языковые функции, чтобы отделить конфиденциальную информацию от остальной части моего источника и, следовательно, сохранить ее от контроля источников. Это то, что я делаю сейчас, но это может быть легко испорчено, по ошибке проверив секретный файл.

Я действительно ищу гарантированный способ гарантировать, что я не делюсь своими привилегиями со всем миром (за исключением Snapchat), который будет бесперебойно работать в процессе разработки, отладки и развертывания, а также быть надежным. Это совершенно нереально. Так что реально я могу сделать?

Технические детали: VS2012, C # 4.5, контроль версий будет либо TF-сервисом, либо GitHub. В настоящее время используется частичный класс для разделения чувствительных ключей в отдельном файле .cs, который не будет добавлен в систему контроля версий. Я думаю, что GitHub может иметь преимущество, так как .gitignore может быть использован, чтобы гарантировать, что частичный файл класса не зарегистрирован, но я облажался с этим раньше. Я надеюсь на «о, общая проблема, вот как вы это делаете», но мне, возможно, придется согласиться на то, «что это не так много, как могло бы», /

Будет
источник
6
Вы можете убедиться, что файл конфигурации, который содержит ваш ключ API, не находится в каталоге, контролируемом исходным кодом, что сделает невозможным его проверку в первую очередь.
Давид Сергей
22
BitBucket.org имеет неограниченные частные репозитории. Свободно. И импортер репозитория gitHub (хранит историю)
Роб ван дер Веер
4
@Dainius Я не доверяю своим разработчикам, потому что я знаю их. Тесно. На самом деле, я по крайней мере близок с собой ... нет, я позволю этому лгать. Но я знаю, как легко это испортить, и как трудно будет почистить историю этого провала.
Будет
15
@Dainius: Да. Я смотрю на каждого персонажа в моей команде. Шутки в сторону. У меня нет выбора. Я не могу кодировать с завязанными глазами. Ненадежно, по крайней мере. Но я делаю, потому что я моя команда. Я Я в КОМАНДЕ. Есть один разработчик, и это я. Я его. Да. Я парень, который собирается все испортить, если он не сделает это правильно. Меня.
Уилл
3
Почему вы пытаетесь скомпилировать ключ в код в первую очередь? Обычно такие вещи помещаются в файл конфигурации.
Донал Феллоуз

Ответы:

128

Не помещайте свою секретную информацию в свой код. Поместите его в файл конфигурации, который читается вашим кодом при запуске. Конфигурационные файлы не должны передаваться на контроль версий, если они не являются «заводскими настройками по умолчанию», и тогда они не должны иметь никакой частной информации.

См. Также вопрос Управление версиями и личный файл конфигурации, чтобы узнать, как это сделать.

Philipp
источник
8
@RobertHarvey, просто не помещая его в систему управления версиями, добавляя правило игнорирования при необходимости. Любой, кто использует программное обеспечение, должен создать свой собственный файл конфигурации со своим собственным ключом API.
Филипп
10
Итак, когда вы собираетесь собрать и создать дистрибутив своего программного обеспечения, как вы можете быть уверены, что оно поставляется с файлом конфигурации? Если у вас нет файла с разумными значениями по умолчанию, обычно не стоит ожидать, что ваш пользователь пройдет через процесс создания файла конфигурации.
Томас Оуэнс
4
Ну, заводские настройки по умолчанию - это одна часть, «установщики» или «мастера первого запуска», другая
Йоханнес
6
Если у многих пользователей есть собственная установка, не должны ли они создавать и использовать свой собственный ключ API? Несколько сайтов / установок с использованием одного и того же ключа, вероятно, плохая идея. Если это всего лишь одна установка, то использование файла конфигурации не является большой проблемой.
Майк Веллер
10
@ Если вы не сможете сделать это из-за непрактичности деталей реализации, я бы сказал, что у вас просто нет подходящего инструментария для развертывания. Развертывание с использованием незафиксированного секретного файла конфигурации должно быть абсолютно безболезненным. Я не могу дать вам конкретного совета, так как я живу в экосистеме Ruby, а не на C #. Но люди из Ruby обычно используют Capistrano для автоматизированного развертывания. Я уверен, что в C # также есть инструмент для автоматического развертывания, и это должно упростить процесс.
Бен Ли
29

Вы можете поместить все закрытые / защищенные ключи как системные переменные окружения. Ваш файл конфигурации будет выглядеть так:

private.key=#{systemEnvironment['PRIVATE_KEY']}

Вот как мы справляемся с этими случаями, и в код ничего не входит. Он работает очень хорошо в сочетании с различными файлами свойств и профилями. Мы используем разные файлы свойств для разных сред. В нашей локальной среде разработки мы помещаем ключи разработки в файлы свойств, чтобы упростить локальную настройку:

private.key=A_DEVELOPMENT_LONG_KEY
Иоаннис Цикас
источник
Это было бы разумным решением, если бы я мог заставить его работать с моим вариантом хостинга. Это не будут переменные среды, но, возможно, некоторые пары конфигурации ключ / значение, которые не будут стерты после публикации ...
Будет ли
Как насчет размещения этих переменных среды на вашем сервере сборки перед отправкой в ​​живую среду? Таким образом, вы будете готовы к производству ресурсов / файлов конфигурации.
Иоаннис Цикас
Сервер сборки - это машина для разработки, поэтому меня беспокоит возможность случайного попадания этой информации в систему контроля версий.
Уилл
Проблема может заключаться в том, что среда может быть прочитана любым пользователем на сервере.
JasonG
Envvars пользователя доступны для чтения только пользователю или пользователю root. (Древние Linux и AIX не делали этого, однако)
Нил МакГиган,
27

Pure Git way

  • .gitignore включенный файл с личными данными
  • Используйте локальную ветку, в которой вы заменяете TEMPLATEнаDATA
  • Используйте грязные / чистые фильтры, в которых (локальный) скрипт фильтра выполняет двунаправленную замену TEMPLATE<->DATA

Ртутный путь

  • MQ-patch (s) поверх фиктивного кода, который заменяется TEMPLATEна DATA(наборы изменений являются общедоступными, patch являются частными)
  • Расширение ключевого слова со специально разработанными ключевыми словами (разворачивается только в вашем рабочем каталоге )

SCM-агностический способ

  • Замена ключевых слов в процессе сборки / развертывания
Ленивый Барсук
источник
Хммм ... Хороший совет git, а ваш независимый совет дает мне хорошую идею ... Я могу использовать события сборки, чтобы ввести файл в процесс публикации, а затем удалить его, помогая убедиться, что он не будет будет случайно добавлен в систему контроля версий ..
Будет ли
7
Нет, нет и еще раз - нет! игнорирование файлов хорошо для добавления какой-то очень специфической настройки для процесса сборки или чего-то еще, но оно никогда не должно использоваться для хранения каких-либо безопасных данных. Не храните защищенные данные в репо, даже если вы их игнорируете.
Шабун
11
@shabunc - RTFM! Проигнорированный файл не сохранен в репо
Ленивый Барсук
9
@LazyBadger - я прекрасно знаю, что это игнорируется. Я также знаю, что, находясь в репо, ВСЕГДА есть шанс, что кто-то по ошибке добавит его в репо. Какой-то внешний путь конфигурации намного лучше.
Шабун
4
@shabunc - хороший момент для сохранения конфигурации вне пути SCM. Вот почему, например, Postgres позволяет обойти проверку паролей, поместив пароль в файл. Но они требуют, чтобы файл паролей был помещен в ~ / .pgpass - который, по-видимому, не является местом, которое очень удобно проверять в системе контроля версий. Они знают, для автоматизации, они должны дать вам оружие, но они упорно трудятся , чтобы держать вас от съемки себя в ногу с ним ..
Стив Midgley
14

Я помещаю секреты в зашифрованный файл (ы), которые я затем фиксирую. Пароль предоставляется при запуске системы или хранится в небольшом файле, который я не фиксирую. Приятно, что Emacs с удовольствием будет управлять этими зашифрованными файлами. Например, файл инициализации emacs включает в себя: (загрузить «secrets.el.gpg»), который просто работает - запрашивает пароль в тех редких случаях, когда я запускаю редактор. Я не беспокоюсь о том, что кто-то нарушит шифрование.

Бен Хайд
источник
3
Это отличное решение - я удивлен, что у вас нет больше голосов за. Я работаю с компанией, которая занимается данными о студентах, которые федерально регулируются в США, поэтому они должны быть особенно осторожны с учетными данными и секретами. Они также являются крупной компанией, поэтому им нужно использовать SCM для учетных данных, чтобы ИТ-специалисты могли находить их и управлять ими после того, как engr их построит. Ваше решение именно то, что они делают. У них есть файлы ключей дешифрования, которые содержат ключи дешифрования для dev / staging / prod / etc (по одному файлу для каждого). Затем все секреты шифруются и проверяются в файлах. Файлы дешифрования используются для получения их в каждой среде.
Стив Мидгли
7
Что ж, в некотором смысле шифрование секрета (в данном случае ключ API) только сдвигает проблему от не фиксации секретных данных к не фиксации парольной фразы (которая теперь становится секретной информацией ). Но, конечно, запросить его при запуске системы - это хороший вариант.
siegi
Мне нравится это решение. Тип зашифрованного файла, который вы фиксируете, может быть файлом KeePass. Он будет иметь запись для каждой среды, используя notesполе для хранения содержимого файла .env. Несколько месяцев назад я написал инструмент, который может читать файл keepass и создавать файл .env, используя notesполе записи. Я думаю о добавлении функции, чтобы я мог сделать это require('switchenv').env()в верхней части программы Node.js и создать переменные process.env на основе записи, которая соответствует NODE_ENV или что-то в этом роде. -> github.com/christiaanwesterbeek/switchenv
Кристиан Вестербик
14

Это очень специфично для Android / Gradle, но вы можете определить ключи в вашем глобальном gradle.propertiesфайле, расположенном в user home/.gradle/. Это также полезно, поскольку вы можете использовать разные свойства в зависимости от buildType или разновидности, т.е. API для dev и разные для релиза.

gradle.properties

MY_PRIVATE_API_KEY=12356abcefg

build.gradle

buildTypes {
        debug{
            buildConfigField("String", "GOOGLE_VERIFICATION_API_KEY", "\"" + MY_PRIVATE_API_KEY +"\"")
            minifyEnabled false
            applicationIdSuffix ".debug"
            }
        }

В коде вы бы сослаться на это

String myAPI = BuildConfig.GOOGLE_VERIFICATION_API_KEY;
scottyab
источник
BuildConfig преобразуется в соответствующий исходный файл, поэтому простой реверс-инжиниринг на вашем apk раскроет все те ключи и секреты, которые вы вложили в BuildConfig
Дмитрий Ливотов
1
Действительно, верный момент. Но вопрос был в том, как сохранить ключи API в исходном коде, а не в двоичном.
Скоттиаб
11

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

Мобильное веб-приложение

Для Android / iPhone устройство должно запрашивать KEY у вашего собственного веб-сервиса при первом запуске приложения. Затем ключ хранится в безопасном месте. Должен ли ключ быть изменен или отозван издателем. Ваш веб-сервис может опубликовать новый ключ.

Размещенное веб-приложение

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

Опубликованный исходный код

Вы храните свой исходный код в общедоступном хранилище, но не KEY. В конфигурации файла вы добавляете строки * поместите ключ сюда * . Когда разработчик использует ваш исходный код, он делает копию sample.cfgфайла и добавляет свой собственный ключ.

Вы не храните свой config.cfgфайл, используемый для разработки или производства в репозитории.

Reactgular
источник
4
Этот вопрос спрашивает, как это сделать, нет, это абсолютно не так. Дело в том, что эти ключи должны использоваться кодом, поэтому к ним должен обращаться код, и это обычно означает, что через код или файлы конфигурации, которые, если они не находятся в исходном коде вместе, они, по крайней мере, находятся рядом и могут случайно оказаться в источник. Размещенное веб-приложение, к сожалению, бессмысленно. Вам не нужно было запрашивать ключ API для входа в StackOverflow через свою (гипотетическую) учетную запись Facebook. ключ места здесь - это огромное упрощение, которое не будет работать в среде dev-> pub, как описано в Q.
Will
Я правильно ответил на вопрос, как и многие другие. Тот факт, что вы не приняли один из них, означает, что вы не понимаете, как работать с этими ключами.
Reactgular
7
Тогда как мы защищаем веб-сервис публикации ключей? Используя другой ключ?
Цзянге Чжан
То же самое сказал @JianggeZhang - это опасный совет
Дэвид К. Хесс
5

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

http://en.wikipedia.org/wiki/Environment_variable

Как их использовать, зависит от языка.

Филипе Джусти
источник
3
Безопасность через неизвестность не рекомендуется для многих. Не могли бы вы уточнить свой ответ, чтобы быть более четким?
2
Это не мрачно, переменные среды доступны только тому пользователю, которого вы добавили, поэтому все ваши учетные данные имеют одинаковую защиту пользовательского контекста, в котором работает ваше приложение. Я обновил ответ, включив в него понятие переменных среды. Это более понятно?
Филипе Джусти
4

Я думаю, что это проблема, с которой у всех когда-то возникали проблемы.

Вот рабочий процесс, который я использовал, который может работать для вас. Он использует .gitignore с изюминкой:

  1. Все конфигурационные файлы находятся в специальной папке (с примерами конфигурационных файлов - необязательно)
  2. Все файлы конфигурации включены в .gitignore, чтобы они не были общедоступными
  3. Настройте сервер gitolite (или ваш любимый сервер git) на личном ящике
  4. Добавить репо со всеми конфигурационными файлами на частном сервере
  5. Добавить скрипт для копирования файлов конфигурации в специальную папку в главном репо (необязательно)

Теперь вы можете клонировать репозиторий config в любую систему разработки и развертывания. Просто запустите скрипт, чтобы скопировать файлы в нужную папку, и все готово.

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

Я использую коробку 15 $ / год для частного git-сервера, но вы также можете установить ее дома, в соответствии с требованием cheapskate ;-)

PS: Вы также можете использовать подмодуль git ( http://git-scm.com/docs/git-submodule ), но я всегда забываю команды, так что быстрые и грязные правила!

Kostas
источник
2

Используйте шифрование, но предоставьте главный ключ при запуске в качестве пароля на консоли, в файле, который может прочитать только пользователь процесса, или из системного хранилища ключей, такого как цепочка ключей Mac OS или хранилище ключей Windows.

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

Эриксон
источник
1

3 стратегии, еще не упомянутые (?)

При регистрации или в предварительной проверке VCS на крючке

  • поиск строк с высокой энтропией, пример обнаружения секретов
  • регулярное выражение для поиска известных шаблонов ключей API. Ключи AWS AKIA * являются примером, git-секреты - это один из инструментов, основанный на этом. Кроме того, имена переменных, такие как «пароль» с постоянным присваиванием.
  • ищите известные секреты - вы знаете свои секреты, ищите текст для них. Или используйте инструмент, я написал это доказательство концепции .

Стратегии уже упоминались

  • хранить в файле за пределами исходного дерева
  • Имейте это в исходном дереве, но скажите VCS игнорировать его
  • Переменные среды представляют собой вариант хранения данных вне исходного дерева.
  • просто не давайте ценные секреты разработчикам
MatthewMartin
источник
0

Храните личную информацию под контролем вашего источника. Создайте незагруженное значение по умолчанию для распространения, и пусть ваша VCS игнорирует реальную. Ваш процесс установки (будь то ручной, настройка / сборка или мастер) должен обрабатывать создание и заполнение нового файла. При необходимости измените права доступа к файлу, чтобы его мог прочитать только требуемый пользователь (веб-сервер?).

Выгоды:

  • Не предполагает разработку объекта == производственный объект
  • Не предполагает, что все соавторы / рецензенты кода являются доверенными
  • Предотвратите легкие ошибки, не допуская контроля версий
  • Простая автоматизация установки с помощью настраиваемой конфигурации для QA / builds

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

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

Адриан Шнайдер
источник
-2

Вместо того, чтобы хранить ключ OAuth в любом месте в виде необработанных данных, почему бы не выполнить строку с помощью какого-либо алгоритма шифрования и сохранить его как соленый хеш? Затем используйте файл конфигурации, чтобы восстановить его во время выполнения. Таким образом, ключ нигде не хранится, хранится ли он в блоке разработки или на самом сервере.

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

Редактировать: Возможно, попробуйте Stanford Javascript Crypto Library , она обеспечивает довольно безопасное симметричное шифрование / дешифрование.

Дэвид Фрейтаг
источник
1
Хеши, как правило, являются односторонним способом. Однако существуют алгоритмы симметричного шифрования, которые будут работать так, как вы предлагаете.
3
Чувак, ты не можешь расшифровать (легко) хеш. В этом весь смысл хэшей. Это для ME, использующего чужой API, где они назначают мне секретный ключ. Мое хеширование гарантирует (если я не выберу плохой алгоритм и не взломаю его каждый раз), что я не смогу использовать их API.
Уилл