Strategia utrzymywania tajnych informacji, takich jak klucze API poza kontrolą źródła?

216

Pracuję nad witryną, która pozwoli użytkownikom zalogować się przy użyciu poświadczeń OAuth takich jak Twitter, Google itp. Aby to zrobić, muszę się zarejestrować u różnych dostawców i uzyskać super tajny klucz API, który mam w celu zabezpieczenia przyrzeczeniami przeciw różnym częściom ciała. Jeśli mój klucz zostanie zasadzony, część zostanie wyrwana.

Klucz API musi podróżować z moim źródłem, ponieważ jest używany w czasie wykonywania do wykonywania żądań uwierzytelnienia. W moim przypadku klucz musi istnieć w aplikacji w pliku konfiguracyjnym lub w samym kodzie. Nie stanowi to problemu, gdy buduję i publikuję z jednego komputera. Jednak kiedy wrzucamy kontrolę źródła do miksu, sprawy stają się bardziej skomplikowane.

Ponieważ jestem tanim dranem, wolałbym korzystać z bezpłatnych usług kontroli źródła, takich jak TFS w chmurze lub GitHub. To pozostawia mi lekką zagadkę:

Jak mogę zachować moje ciało nienaruszone, gdy moje klucze API znajdują się w moim kodzie, a mój kod jest dostępny w publicznym repozytorium?

Mogę wymyślić wiele sposobów, aby sobie z tym poradzić, ale żaden z nich nie jest tak satysfakcjonujący.

  • Mogę usunąć wszystkie prywatne informacje z kodu i edytować je ponownie po wdrożeniu. Byłby to poważny ból do wdrożenia (nie będę szczegółowo opisywać wielu sposobów) i nie jest opcją.
  • Mógłbym to zaszyfrować. Ale ponieważ muszę go odszyfrować, każdy ze źródłem może wymyślić, jak to zrobić. Bezcelowy.
  • Mógłbym zapłacić za prywatną kontrolę źródła. LOL j / k wydawać pieniądze? Proszę.
  • Mógłbym użyć funkcji językowych, aby oddzielić wrażliwe informacje od reszty mojego źródła, a tym samym uniemożliwić kontrolę źródła. To właśnie robię teraz, ale można to łatwo zepsuć, błędnie sprawdzając tajny plik.

Naprawdę szukam gwarantowanego sposobu, aby upewnić się, że nie podzielę się swoimi prywatnymi osobami ze światem (z wyjątkiem Snapchata), który będzie działał płynnie poprzez programowanie, debugowanie i wdrażanie, a także będzie niezawodny. To jest całkowicie nierealne. Co więc realistycznie mogę zrobić?

Szczegóły techniczne: VS2012, C # 4.5, kontrola źródła będzie usługą TF lub GitHub. Obecnie używamy częściowej klasy do podziału wrażliwych kluczy w osobnym pliku .cs, który nie zostanie dodany do kontroli źródła. Myślę, że GitHub może mieć tę zaletę, że .gitignore może być użyty do zapewnienia, że ​​plik klasy częściowej nie jest rejestrowany, ale wcześniej to spieprzyłem. Mam nadzieję na „och, wspólny problem, oto jak to robisz”, ale być może będę musiał zadowolić się tym, „że nie jest do bani tak bardzo, jak mogłoby to mieć”,: /

Będzie
źródło
6
Możesz upewnić się, że plik konfiguracyjny zawierający klucz API nie znajduje się w katalogu kontrolowanym przez źródło, co uniemożliwi sprawdzenie go na pierwszym miejscu.
David Sergey
22
BitBucket.org ma nieograniczone prywatne repozytoria. Wolny. I importer repozytorium gitHub (przechowuje historię)
Rob van der Veer
4
@Dainius Nie ufam moim programistom, ponieważ ich znam. Ściśle Tak naprawdę jestem blisko siebie przynajmniej ... nie, pozwolę temu kłamać. Ale wiem, jak łatwo jest spieprzyć i jak trudno będzie wyszorować historię tego pomyłki.
Czy
15
@Dainius: Tak. Patrzę na każdą postać, którą koduje mój zespół. Poważnie. Nie mam wyboru. Nie mogę kodować z zasłoniętymi oczami. Przynajmniej nie niezawodnie. Ale robię to, bo jestem moim zespołem. Jestem I w TEAM. Jest jeden programista i to ja. Jestem nim Tak. Jestem facetem, który to wszystko spieprzy, jeśli nie zrobi tego dobrze. Mnie.
Czy
3
Dlaczego w pierwszej kolejności próbujesz skompilować klucz w kodzie? Zazwyczaj umieszcza się tego rodzaju w pliku konfiguracyjnym.
Donal Fellows

Odpowiedzi:

127

Nie umieszczaj swoich tajnych informacji w kodzie. Umieść go w pliku konfiguracyjnym, który jest odczytywany przez kod podczas uruchamiania. Pliki konfiguracyjne nie powinny być poddawane kontroli wersji, chyba że są „domyślnymi ustawieniami fabrycznymi”, a następnie nie powinny zawierać żadnych prywatnych informacji.

Zobacz także pytanie Kontrola wersji i osobisty plik konfiguracyjny, aby dowiedzieć się, jak to zrobić dobrze.

Philipp
źródło
8
@RobertHarvey, po prostu nie nakładając go na kontrolę wersji, dodając w razie potrzeby regułę ignorowania. Każdy korzystający z oprogramowania musi zbudować własny plik konfiguracyjny z własnym kluczem API.
Philipp
10
Kiedy więc budujesz i tworzysz dystrybucję swojego oprogramowania, skąd masz pewność, że jest ono dostarczane z plikiem konfiguracyjnym? O ile nie masz pliku z rozsądnymi ustawieniami domyślnymi, zwykle nie jest rozsądne oczekiwać, że użytkownik przejdzie proces tworzenia pliku konfiguracyjnego.
Thomas Owens
4
Domyślne ustawienia fabryczne to jedna część, „instalatorzy” lub „kreatory pierwszego uruchomienia” to kolejna część
John
6
Jeśli wielu użytkowników ma własną instalację, czy nie powinni tworzyć i używać własnego klucza API? Wiele witryn / instalacji korzystających z tego samego klucza jest prawdopodobnie złym pomysłem. Jeśli jest to tylko jedna instalacja, korzystanie z pliku konfiguracyjnego nie stanowi dużego problemu.
Mike Weller,
10
@Will, jeśli nie możesz tego zrobić z powodu niepraktyczności szczegółów implementacji, powiedziałbym, że po prostu nie masz odpowiedniego oprzyrządowania do wdrożenia. Wdrożenie przy użyciu niezatwierdzonego tajnego pliku konfiguracyjnego powinno być całkowicie bezbolesne. Nie mogę zaoferować konkretnej porady, ponieważ mieszkam w ekosystemie Ruby, a nie w języku C #. Ale ludzie Ruby używają Capistrano do automatycznych wdrożeń. Jestem pewien, że C # ma również swoje narzędzie do automatycznego wdrażania, co powinno ułatwić proces.
Ben Lee,
29

Możesz umieścić wszystkie klucze prywatne / chronione jako systemowe zmienne środowiskowe. Twój plik konfiguracyjny będzie wyglądał następująco:

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

W ten sposób radzimy sobie z tymi przypadkami i nic nie wchodzi w kod. Działa bardzo dobrze w połączeniu z różnymi plikami właściwości i profilami. Używamy różnych plików właściwości dla różnych środowisk. W naszym lokalnym środowisku programistycznym umieszczamy klucze programistyczne w plikach właściwości, aby uprościć lokalną konfigurację:

private.key=A_DEVELOPMENT_LONG_KEY
Ioannis Tzikas
źródło
Byłoby to rozsądne rozwiązanie, jeśli mogę zmusić go do pracy z moją opcją hostingu. Nie będą to zmienne środowiskowe, ale być może niektóre pary konfiguracji klucz / wartość, które nie zostaną usunięte po opublikowaniu ...
Will
Co powiesz na umieszczenie tych zmiennych środowiskowych na serwerze kompilacji przed wysyłką do środowiska na żywo? W ten sposób będziesz gotowy na zasoby produkcyjne / pliki konfiguracyjne.
Ioannis Tzikas
Serwer kompilacji jest maszyną programistyczną, dlatego martwię się, że te informacje mogą przypadkowo zostać włączone do kontroli źródła.
Czy
Problemem może być to, że środowisko jest czytelne dla każdego na serwerze.
JasonG
Envvary użytkownika są czytelne tylko dla użytkownika lub użytkownika root. (Starożytny Linux i AIX tego jednak nie zrobili)
Neil McGuigan
27

Sposób Pure Git

  • .gitignore dołączony plik z prywatnymi danymi
  • Użyj lokalnego oddziału, w którym wymienić TEMPLATEzDATA
  • Użyj filtrów rozmazywania / czyszczenia, w których skrypt (lokalny) filtra wykonuje dwukierunkową zamianę TEMPLATE<->DATA

Rtęciowy sposób

  • Łatki MQ na szczycie fałszywego kodu, które zastępują TEMPLATEsię DATA(zestawy zmian są publiczne, łatka jest prywatna)
  • Rozszerzenie słowa kluczowego o specjalnie zaprojektowane słowa kluczowe (rozwinięte tylko w katalogu roboczym )

Metoda agnostyczna SCM

  • Zamień słowa kluczowe w ramach procesu kompilacji / wdrażania
Leniwy Borsuk
źródło
Hmmm ... rada git jest dobra, a twoja rada agnostyczna daje mi dobry pomysł ... mogę użyć zdarzeń kompilacji, aby wprowadzić plik do procesu publikowania, a następnie usunąć go później, co pomoże zapewnić, że nie będzie zostać przypadkowo dodany do kontroli źródła.
Czy
7
Nie, nie i jeszcze raz - nie! ignorowanie plików jest przydatne do dodawania bardzo specyficznych dostosowań do procesu budowania lub czegoś takiego, ale nigdy nie powinno się go używać do przechowywania jakichkolwiek bezpiecznych danych. Nie przechowuj bezpiecznych danych w repozytorium, nawet jeśli je ignorujesz.
shabunc
11
@shabunc - RTFM! Zignorowany plik nie jest przechowywany w repozytorium
Lazy Badger
9
@LazyBadger - Wiem całkiem dobrze, że jest ignorowany. Wiem też, że będąc w repozytorium, ZAWSZE istnieje szansa, że ​​ktoś bez wątpienia doda to w jakiś sposób do repo. Niektóre zewnętrzne ścieżki konfiguracji są znacznie lepsze.
shabunc
4
@shabunc - dobry punkt na utrzymanie konfiguracji poza ścieżką SCM. Dlatego na przykład Postgres pozwala ominąć sprawdzanie hasła poprzez umieszczenie hasła w pliku. Wymagają jednak umieszczenia pliku haseł w ~ / .pgpass - co prawdopodobnie nie jest lokalizacją, która jest bardzo dogodna do sprawdzenia kontroli źródła. Wiedzą, że w celu automatyzacji muszą dać ci broń, ale ciężko pracują, aby powstrzymać cię od strzelania sobie nią w stopę.
Steve Midgley
14

Wkładam sekrety do zaszyfrowanych plików, które następnie popełniam. Hasło jest podawane podczas uruchamiania systemu lub jest przechowywane w małym pliku, którego nie zatwierdzam. Fajnie, że Emacs z radością zarządza tymi zaszyfrowanymi plikami. Na przykład plik inicjujący emacsa zawiera: (ładuje „secrets.el.gpg”), co po prostu działa - monitując mnie o hasło w tych rzadkich przypadkach, gdy uruchamiam edytor. Nie martwię się o to, że ktoś złamie szyfrowanie.

Ben Hyde
źródło
3
To świetne rozwiązanie - jestem zaskoczony, że nie masz więcej głosów. Współpracuję z firmą zajmującą się danymi studenckimi, która jest federalnie regulowana w Stanach Zjednoczonych, więc muszą oni być bardzo ostrożni w zakresie poświadczeń i tajemnic. Są także dużą firmą, dlatego muszą używać SCM do poświadczeń, aby dział IT mógł je znaleźć / zarządzać po ich kompilacji. Twoje rozwiązanie jest dokładnie tym, co robią. Mają pliki kluczy odszyfrowujących, które zawierają klucze odszyfrowywania dla dev / staging / prod / etc (jeden plik dla każdego). Następnie wszystkie sekrety są szyfrowane i zapisywane w plikach. Pliki odszyfrowujące są używane do uzyskania ich w każdym środowisku.
Steve Midgley,
7
Cóż, w pewnym sensie szyfrowanie tajnego klucza (w tym przypadku klucza API) zmienia jedynie problem z nieprzekazywania tajnych danych na nieprzekazywanie hasła (które teraz staje się tajnymi danymi ). Ale oczywiście poproszenie o to przy uruchomieniu systemu jest dobrą opcją.
siegi
Podoba mi się to rozwiązanie. Rodzaj zaszyfrowanego pliku, który zatwierdzasz, może być plikiem KeePass. Będzie miał wpis dla każdego środowiska, używając notespola do przechowywania zawartości pliku .env. Kilka miesięcy temu napisałem narzędzie, które może odczytać plik keepass i utworzyć plik .env za pomocą notespola wpisu. Zastanawiam się nad dodaniem funkcji, dzięki której będę mógł robić require('switchenv').env()w górnej części programu Node.js i tworzyć zmienne process.env na podstawie wpisu pasującego do NODE_ENV lub coś w tym rodzaju. -> github.com/christiaanwesterbeek/switchenv
Christiaan Westerbeek
14

Jest to bardzo specyficzne dla Androida / Gradle, ale możesz zdefiniować klucze w gradle.propertiespliku globalnym znajdującym się w user home/.gradle/. Jest to również przydatne, ponieważ można używać różnych właściwości w zależności od buildType lub smaku, tj. API dla deweloperów i różnych dla wydania.

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"
            }
        }

W kodzie będziesz się tak odwoływał

String myAPI = BuildConfig.GOOGLE_VERIFICATION_API_KEY;
szkocja
źródło
BuildConfig tłumaczy na odpowiedni plik źródłowy, więc prosta inżynieria odwrotna w twojej aplikacji ujawni wszystkie te klucze i sekrety, które umieściłeś w BuildConfig
Dmitri Livotov
1
Rzeczywiście, ważny punkt. Ale pytanie dotyczyło tego, jak trzymać klucze API poza kodem źródłowym, a nie binarnym.
scottyab
11

Nie należy rozpowszechniać tego klucza w aplikacji ani przechowywać go w repozytorium kodu źródłowego. To pytanie dotyczy tego, jak to zrobić, i nie jest to zwykle wykonywane.

Mobilna aplikacja internetowa

W przypadku systemu Android / iPhone urządzenie powinno poprosić o KLUCZ z własnego serwisu internetowego przy pierwszym uruchomieniu aplikacji. Klucz jest następnie przechowywany w bezpiecznym miejscu. Jeśli klucz zostanie zmieniony lub odwołany przez wydawcę. Twój serwis internetowy może opublikować nowy klucz.

Hostowana aplikacja internetowa

Klienci korzystający z licencji na oprogramowanie będą musieli ręcznie wprowadzić klucz przy pierwszej konfiguracji oprogramowania. Możesz dać każdemu ten sam klucz, inny klucz lub otrzymać własny.

Opublikowano kod źródłowy

Przechowujesz swój kod źródłowy w publicznym repozytorium, ale nie KLUCZ. W konfiguracji pliku dodajesz linie * umieść tutaj klucz * . Gdy programista używa kodu źródłowego, tworzy kopię sample.cfgpliku i dodaje własny klucz.

Nie przechowujesz config.cfgpliku w repozytorium w celu programowania lub produkcji.

Reactgular
źródło
4
To pytanie brzmi: jak to zrobić , absolutnie NIE. Faktem jest, że klucze te muszą być używane przez kod, a zatem można uzyskać do nich dostęp za pomocą kodu, a to zwykle oznacza za pomocą kodu lub plików konfiguracyjnych, które, jeśli nie są razem w źródle, są przynajmniej blisko i mogą przypadkowo skończyć w źródło. Hostowana aplikacja internetowa jest niestety bezsensowna. Nie trzeba było ubiegać się o klucz interfejsu API, aby zalogować się do StackOverflow za pośrednictwem (hipotetycznego) konta na Facebooku. kluczem tutaj jest ogromne uproszczenie, które nie będzie działać w środowiskach dev-> pub, jak opisano w Q.
Will
Odpowiedziałem poprawnie na pytanie, podobnie jak wiele innych. Fakt, że nie zaakceptowałeś jednego z nich oznacza, że ​​nie rozumiesz, jak pracować z tymi kluczami.
Reactgular,
7
W jaki więc sposób chronimy usługę internetową wydawców kluczy? Używasz innego klucza?
Jiangge Zhang
To samo powiedział @JianggeZhang - to niebezpieczna rada
David K. Hess,
5

Użyj zmiennych środowiskowych do tajnych rzeczy, które zmieniają się dla każdego serwera.

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

Sposób ich użycia zależy od języka.

Filipe Giusti
źródło
3
Bezpieczeństwo przez zaciemnienie nie jest zalecanym podejściem dla wielu. Czy chciałbyś bardziej szczegółowo wyjaśnić swoją odpowiedź?
2
To nie jest niejasne, zmienne środowiskowe są dostępne tylko dla dodanego użytkownika, więc wszystkie poświadczenia mają taką samą ochronę kontekstu użytkownika, w którym działa Twoja aplikacja. Zaktualizowałem odpowiedź, aby uwzględnić pojęcie zmiennych środowiskowych. Czy to jest bardziej jasne?
Filipe Giusti
4

Myślę, że jest to problem, z którym wszyscy mieli kiedyś problemy.

Oto przepływ pracy, który wykorzystałem, który może działać dla Ciebie. Używa .gitignore z niespodzianką:

  1. Wszystkie pliki konfiguracyjne znajdują się w specjalnym folderze (z przykładowymi plikami konfiguracyjnymi - opcjonalnie)
  2. Wszystkie pliki konfiguracyjne są zawarte w .gitignore, aby nie były publiczne
  3. Skonfiguruj serwer gitolite (lub ulubiony serwer git) na prywatnym urządzeniu
  4. Dodaj repozytorium ze wszystkimi plikami konfiguracyjnymi na prywatnym serwerze
  5. Dodaj skrypt, aby skopiować pliki konfiguracyjne do specjalnego folderu w głównym repozytorium (opcjonalnie)

Teraz możesz sklonować repozytorium konfiguracji do dowolnego systemu programowania i wdrażania. Wystarczy uruchomić skrypt, aby skopiować pliki do odpowiedniego folderu i gotowe.

Nadal dostajesz wszystkie cukierki GitHub, dzielisz się swoim kodem ze światem, a wrażliwe dane nigdy nie są w głównym repozytorium, więc nie są upubliczniane. Nadal są tylko wyciągnięciem i kopią z dowolnego systemu wdrażania.

Używam skrzynki 15 $ / rok dla prywatnego serwera git, ale możesz też skonfigurować jeden w domu, zgodnie z wymaganiami Cheapskate ;-)

PS: Możesz również użyć submodułu git ( http://git-scm.com/docs/git-submodule ), ale zawsze zapominam o poleceniach, więc szybkie i brudne reguły!

Kostas
źródło
2

Użyj szyfrowania, ale podczas uruchamiania podaj klucz główny jako hasło w konsoli, w pliku, który tylko użytkownik procesu może odczytać, lub z magazynu kluczy dostarczonego przez system, takiego jak pęku kluczy systemu Mac OS lub magazynu kluczy systemu Windows.

W celu ciągłej dostawy potrzebne są gdzieś zapisane różne klucze. Konfiguracja powinna być oddzielona od kodu, ale sensowne jest utrzymywanie jej pod kontrolą wersji.

erickson
źródło
1

3 strategie, o których jeszcze nie wspomniano (?)

Przy odprawie lub w haku VCS do kontroli wstępnej

  • szukaj ciągów o wysokiej entropii, na przykład wykrywaj sekrety
  • Wyszukaj wyrażenia regularne dla dobrze znanych wzorców kluczy API. Klucze AKIA * AWS są przykładem, git-secrets to jedno narzędzie oparte na tym. Ponadto nazwy zmiennych, takie jak „hasło” ze stałym przypisywaniem.
  • szukaj znanych sekretów - znasz swoje sekrety, szukaj ich tekstu. Lub użyj narzędzia, napisałem ten dowód koncepcji .

Strategie już wspomniane

  • przechowywać w pliku poza drzewem źródłowym
  • mieć je w drzewie źródłowym, ale powiedz VCS, aby je zignorowało
  • zmienne środowiskowe są odmianą przechowywania danych poza drzewem źródłowym
  • po prostu nie daj cennych tajemnic deweloperom
MatthewMartin
źródło
0

Trzymaj prywatne informacje poza kontrolą źródła. Utwórz nieobciążone domyślne ustawienie dla dystrybucji i niech twój VCS zignoruje prawdziwy. Twój proces instalacji (ręczny, konfiguracyjny / kompilacyjny lub kreator) powinien obsłużyć tworzenie i wypełnianie nowego pliku. Opcjonalnie zmodyfikuj uprawnienia do pliku, aby zapewnić, że tylko wymagany użytkownik (serwer internetowy?) Może go odczytać.

Korzyści:

  • Nie zakłada bytu programistycznego == bytu produkcyjnego
  • Nie zakłada się, że wszyscy współpracownicy / recenzenci kodu są zaufani
  • Zapobiegaj łatwym błędom, utrzymując je poza kontrolą wersji
  • Łatwa do zautomatyzowania instalacja z niestandardową konfiguracją dla kontroli jakości / kompilacji

Jeśli już to robisz i przypadkowo je zameldujesz, dodaj je do projektu .gitignore. Uniemożliwi to powtórzenie.

Wokół jest wiele darmowych hostów Git, które zapewniają prywatne repozytoria. Chociaż nigdy nie powinieneś aktualizować swoich danych uwierzytelniających, możesz być tani i mieć również prywatne repozytoria. ^ _ ^

Adrian Schneider
źródło
-2

Zamiast mieć gdziekolwiek klucz OAuth przechowywany jako surowe dane, dlaczego nie uruchomić łańcucha przez jakiś algorytm szyfrujący i zapisać go jako solony skrót? Następnie użyj pliku konfiguracyjnego, aby przywrócić go w czasie wykonywania. W ten sposób klucz nie jest nigdzie przechowywany, niezależnie od tego, czy jest przechowywany na pudełku programistycznym, czy na samym serwerze.

Możesz nawet utworzyć interfejs API, dzięki któremu Twój serwer automatycznie wygeneruje nowy solony i zakodowany klucz API na podstawie żądania, w ten sposób nawet twój zespół nie będzie widział źródła OAuth.

Edycja: Być może wypróbuj bibliotekę kryptograficzną Javascript Stanford , pozwala ona na dość bezpieczne szyfrowanie / deszyfrowanie symetryczne.

David Freitag
źródło
1
Hashe to na ogół sposób jednokierunkowy. Istnieją jednak algorytmy szyfrowania symetrycznego, które działałyby tak, jak sugerujesz.
3
Stary, nie możesz odszyfrować (łatwo) skrótu. To jest sedno haszy. To jest dla ME korzystającego z czyjegoś API, gdzie przypisuje mi tajny klucz. Moje haszowanie zapewnia (chyba że wybiorę słabe algo i łamię go za każdym razem), że nie mogę używać ich API.
Czy