Strategia per mantenere informazioni segrete come le chiavi API fuori dal controllo del codice sorgente?


217

Sto lavorando su un sito Web che consentirà agli utenti di accedere utilizzando le credenziali OAuth come Twitter, Google, ecc. Per fare questo, devo registrarmi con questi vari provider e ottenere una chiave API super segreta che ho per proteggere con impegni contro varie parti del corpo. Se la mia chiave viene strappata, la parte viene strappata.

La chiave API deve viaggiare con la mia fonte, poiché viene utilizzata in fase di esecuzione per eseguire richieste di autenticazione. Nel mio caso, la chiave deve esistere all'interno dell'applicazione in un file di configurazione o all'interno del codice stesso. Questo non è un problema quando creo e pubblico da una singola macchina. Tuttavia, quando gettiamo il controllo del codice sorgente nel mix, le cose diventano più complicate.

Dato che sono un bastardo economico, preferirei di gran lunga utilizzare i servizi di controllo del codice sorgente gratuiti come TFS nel cloud o GitHub. Questo mi lascia con un leggero enigma:

Come posso mantenere intatto il mio corpo quando le mie chiavi API sono nel mio codice e il mio codice è disponibile in un repository pubblico?

Posso pensare a diversi modi per gestirlo, ma nessuno di loro è così soddisfacente.

  • Potrei rimuovere tutte le informazioni private dal codice e modificarle nuovamente dopo la distribuzione. Questo sarebbe un grave dolore da implementare (non descriverò in dettaglio i molti modi) e non è un'opzione.
  • Potrei crittografarlo. Ma come devo decifrarlo, chiunque abbia la fonte potrebbe capire come farlo. Inutile.
  • Potrei pagare per il controllo della fonte privata. LOL j / k spendi soldi? Per favore.
  • Potrei usare le funzionalità del linguaggio per separare le informazioni sensibili dal resto della mia fonte e quindi mantenerle dal controllo della fonte. Questo è quello che sto facendo ora, ma potrebbe essere facilmente rovinato controllando erroneamente il file segreto.

Sto davvero cercando un modo garantito per assicurarmi di non condividere i miei privati ​​con il mondo (tranne su Snapchat) che funzioneranno senza problemi attraverso lo sviluppo, il debug e l'implementazione e che siano anche infallibili. Questo è completamente irrealistico. Quindi cosa realisticamente posso fare?

Dettagli tecnici: VS2012, C # 4.5, il controllo del codice sorgente sarà TF service o GitHub. Attualmente si utilizza una classe parziale per dividere le chiavi sensibili in un file .cs separato che non verrà aggiunto al controllo del codice sorgente. Penso che GitHub possa avere il vantaggio in quanto .gitignore potrebbe essere usato per garantire che il file di classe parziale non sia archiviato, ma l'ho rovinato prima. Spero in un "oh, problema comune, ecco come lo fai", ma potrei accontentarmi di "che non fa schifo quanto potrebbe avere",: /


6
Puoi assicurarti che quel file di configurazione che contiene la tua chiave API non sia nella directory controllata dal codice sorgente, il che renderà impossibile controllarlo al primo posto.
David Sergey,

22
BitBucket.org ha repository privati ​​illimitati. Gratuito. E importatore di repository gitHub (mantiene la storia)
Rob van der Veer,

4
@Dainius Non mi fido dei miei sviluppatori perché li conosco. Intimamente. In effetti, sono intimo con me stesso almeno ... no, lascerò mentire. Ma so quanto sia facile rovinare e quanto sarà difficile ripulire la storia di quel disastro.
Sarà il

15
@Dainius: Sì. Guardo ogni singolo personaggio che la mia squadra codifica. Sul serio. Non ho scelta. Non riesco a programmare con gli occhi bendati. Almeno non in modo affidabile. Ma lo faccio, perché sono la mia squadra. Sono l'io in SQUADRA. C'è uno sviluppatore ed sono io. Sono lui Sì. Sono il ragazzo che rovinerà tutto se non lo fa nel modo giusto. Me.
Sarà il

3
Perché stai provando a compilare la chiave nel codice in primo luogo? È normale inserire questo genere di cose in un file di configurazione.
Donal Fellows,

Risposte:


128

Non inserire le tue informazioni segrete nel tuo codice. Inseriscilo in un file di configurazione che viene letto dal tuo codice all'avvio. I file di configurazione non dovrebbero essere messi sul controllo versione, a meno che non siano "valori predefiniti di fabbrica" ​​e quindi non dovrebbero avere alcuna informazione privata.

Vedi anche la domanda Controllo della versione e file di configurazione personale per come farlo bene.


8
@RobertHarvey semplicemente non inserendolo nel controllo versione, aggiungendo una regola ignora quando necessario. Chiunque utilizzi il software deve creare il proprio file di configurazione con la propria chiave API.
Philipp,

10
Quindi, quando vai a compilare e creare una distribuzione del tuo software, come sei sicuro che venga spedito con un file di configurazione? A meno che non si disponga di alcuni file con impostazioni predefinite ragionevoli, di solito non è ragionevole aspettarsi che l'utente esegua un processo di creazione di un file di configurazione.
Thomas Owens

4
Bene, le impostazioni di fabbrica sono una parte, "installatori" o "maghi di prima esecuzione" un'altra
johannes

6
Se molti utenti hanno la propria installazione, non dovrebbero creare e utilizzare la propria chiave API? Più siti / installazioni che utilizzano la stessa chiave sono probabilmente una cattiva idea. Se si tratta di una sola installazione, l'utilizzo di un file di configurazione non è una seccatura.
Mike Weller,

10
@Will, se non puoi farlo a causa dell'impraticabilità dei dettagli di implementazione, direi che semplicemente non hai gli strumenti adeguati per la distribuzione. La distribuzione utilizzando un file di configurazione segreto non impegnato deve essere completamente indolore. Non posso offrirti consigli specifici poiché vivo nell'ecosistema Ruby, non in C #. Ma i rubini tendono a usare Capistrano per distribuzioni automatizzate. Sono sicuro che C # disponga anche del suo strumento per la distribuzione automatizzata e questo dovrebbe rendere il processo semplice.
Ben Lee,

29

È possibile inserire tutte le chiavi private / protette come variabili di ambiente di sistema. Il tuo file di configurazione sarà simile al seguente:

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

Questo è il modo in cui gestiamo questi casi e niente va nel codice. Funziona molto bene combinato con diversi file di proprietà e profili. Utilizziamo file di proprietà diversi per ambienti diversi. Nel nostro ambiente di sviluppo locale inseriamo le chiavi di sviluppo nei file delle proprietà per semplificare l'installazione locale:

private.key=A_DEVELOPMENT_LONG_KEY

Questa sarebbe una soluzione ragionevole se riesco a farlo funzionare con la mia opzione di hosting. Non saranno variabili d'ambiente, ma forse alcune coppie di configurazione chiave / valore che non vengono cancellate dopo la pubblicazione ...
Will

Che ne dici di mettere quelle variabili d'ambiente nel tuo server di build prima di spedire nell'ambiente live? In questo modo sarai pronto per i file di configurazione / risorse di produzione.
Ioannis Tzikas,

Il server di build è la macchina di sviluppo, motivo per cui sono preoccupato per queste informazioni che potrebbero essere verificate accidentalmente nel controllo del codice sorgente.
Sarà il

Il problema potrebbe essere che l'ambiente è leggibile da chiunque sul server.
JasonG,

Gli utenti di un utente sono leggibili solo dall'utente o dal root. (Comunque, Ancient Linux e AIX non lo fecero)
Neil McGuigan il

27

Modo Git puro

  • .gitignore file incluso con dati privati
  • Utilizzare una filiale locale, in cui si sostituisce TEMPLATEconDATA
  • Utilizza i filtri di sfumatura / pulizia, in cui lo script del filtro (locale) esegue la sostituzione bidirezionale TEMPLATE<->DATA

Modo mercuriale

  • Patch MQ sopra il codice fittizio, che sostituisce TEMPLATEcon DATA(i changeset sono pubblici, la patch è privata)
  • Estensione delle parole chiave con parole chiave appositamente progettate (espanse solo nella directory di lavoro )

Modo agnostico SCM

  • Sostituzione delle parole chiave come parte del processo di compilazione / distribuzione

Hmmm ... Il consiglio git è buono, e il tuo consiglio agnostico mi dà una buona idea ... Posso usare eventi build per introdurre il file nel processo di pubblicazione, quindi rimuoverlo dopo, contribuendo così a garantire che non lo farà essere accidentalmente aggiunto al controllo del codice sorgente.
Sarà il

7
No, no e ancora una volta - no! ignorare i file è utile per aggiungere una personalizzazione molto specifica al processo di compilazione o qualcosa del genere, ma non dovrebbe mai essere utilizzato per archiviare dati sicuri. Non archiviare dati sicuri in repository, anche se li stai ignorando.
shabunc,

11
@shabunc - RTFM! File ignorato non archiviato in repository
Lazy Badger

9
@LazyBadger - So abbastanza bene che viene ignorato. So anche che, essendo in repo, c'è SEMPRE la possibilità che qualcuno, per sbaglio, lo aggiunga in qualche modo al repository. Qualche percorso di configurazione esterno è molto meglio.
Shabunc,

4
@shabunc - buon punto per mantenere la configurazione fuori dal percorso SCM. Ecco perché, ad esempio, Postgres ti consente di ignorare i controlli della password inserendo la password in un file. Ma richiedono che il file delle password sia inserito in ~ / .pgpass - che presumibilmente non è un percorso molto comodo da controllare nel controllo del codice sorgente. Sanno che, per l'automazione, devono darti una pistola, ma lavorano sodo per impedirti di spararti al piede con esso ..
Steve Midgley,

14

Ho messo segreti in file crittografati che poi commetto. La passphrase viene fornita all'avvio del sistema oppure viene archiviata in un piccolo file che non eseguo il commit. È bello che Emacs gestirà allegramente questi file crittografati. Ad esempio, il file emacs init include: (carica "secrets.el.gpg"), che funziona e mi chiede la password in quelle rare occasioni quando avvio l'editor. Non mi preoccupo che qualcuno rompa la crittografia.


3
Questa è un'ottima soluzione - sono sorpreso che tu non abbia più voti positivi. Lavoro con un'azienda che si occupa dei dati degli studenti, che è regolamentata a livello federale negli Stati Uniti, quindi devono fare molta attenzione con credenziali e segreti. Sono anche una grande azienda, quindi devono utilizzare SCM per le credenziali in modo che l'IT possa trovarle / gestirle dopo che engr le ha costruite. La tua soluzione è esattamente ciò che fanno. Hanno file di decrittografia che contengono chiavi di decrittografia per dev / staging / prod / etc (un file per ciascuno). Quindi tutti i segreti vengono crittografati e registrati in file. I file di decrittografia vengono utilizzati per ottenerli in ogni ambiente.
Steve Midgley,

7
Bene, in un certo senso la crittografia del segreto (chiave API in questo caso) sposta solo il problema dal non commettere i dati segreti al non commettere la passphrase (che ora diventa i dati segreti ). Ma ovviamente, chiederlo all'avvio del sistema è una buona opzione.
siegi,

Mi piace questa soluzione. Il tipo di file crittografato che commetti potrebbe essere un file KeePass. Avrebbe una voce per ogni ambiente, usando il notescampo per memorizzare il contenuto del file .env. Qualche mese fa ho scritto uno strumento in grado di leggere un file keepass e creare un file .env usando il notescampo di una voce. Sto pensando di aggiungere una funzione in modo da poterlo eseguire require('switchenv').env()nella parte superiore del programma Node.js e creare variabili process.env in base alla voce corrispondente a NODE_ENV o qualcosa del genere. -> github.com/christiaanwesterbeek/switchenv
Christiaan Westerbeek

14

Questo è molto specifico per Android / Gradle ma potresti definire le chiavi nel tuo gradle.propertiesfile globale che si trova in user home/.gradle/. Ciò è utile anche in quanto è possibile utilizzare proprietà diverse a seconda di buildType o flavour, ad esempio API per sviluppo e diverso per rilascio.

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

Nel codice faresti riferimento in questo modo

String myAPI = BuildConfig.GOOGLE_VERIFICATION_API_KEY;

BuildConfig si traduce nel corrispondente file sorgente, quindi una semplice ingegneria inversa sul tuo apk rivelerà tutte quelle chiavi e segreti che hai inserito in BuildConfig
Dmitri Livotov

1
Anzi, un punto valido. Ma la domanda era su come mantenere le chiavi API fuori dal codice sorgente e non dal file binario.
scottyab

11

Non dovresti distribuire quella chiave con la tua applicazione o archiviarla nel repository del codice sorgente. Questa domanda è chiedersi come farlo, e non è quello che si fa normalmente.

Applicazione Web mobile

Per Android / iPhone il dispositivo deve richiedere il TASTO al proprio servizio Web al primo avvio dell'app. La chiave viene quindi memorizzata in un luogo sicuro. La chiave deve essere modificata o revocata dall'editore. Il tuo servizio web può pubblicare una nuova chiave.

Applicazione Web ospitata

I clienti che utilizzano una licenza del proprio software dovranno inserire manualmente la chiave al momento della prima configurazione del software. Puoi dare a tutti la stessa chiave, chiavi diverse o ottengono le proprie.

Codice sorgente pubblicato

Memorizzi il tuo codice sorgente in un repository pubblico ma non KEY. Nella configurazione del file aggiungi le righe * inserisci la chiave qui * . Quando uno sviluppatore utilizza il codice sorgente, crea una copia del sample.cfgfile e aggiunge la propria chiave.

Non conservare il config.cfgfile utilizzato per lo sviluppo o la produzione nel repository.


4
Questa domanda è chiedersi come farlo no, assolutamente no. Il fatto è che queste chiavi devono essere usate dal codice, quindi sono accessibili dal codice, e di solito ciò significa tramite il codice o i file di configurazione, che se non sono nel sorgente insieme sono almeno vicini e possono finire accidentalmente in fonte. Sfortunatamente, l'app Web ospitata non ha senso. Non è stato necessario richiedere una chiave API per accedere a StackOverflow tramite il tuo (ipotetico) account Facebook. posto chiave qui è un'enorme semplificazione eccessiva che non funzionerà in ambienti dev-> pub, come è descritto nel Q.
Will

Ho risposto correttamente alla domanda, come molti altri. Il fatto che tu non abbia accettato uno di essi implica che non capisci come lavorare con queste chiavi.
Reactgular,

7
Quindi come proteggiamo il servizio Web di pubblicazione delle chiavi? Usi un'altra chiave?
Jiangge Zhang,

Idem quello che ha detto @JianggeZhang - questo è un consiglio pericoloso
David K. Hess il

5

Utilizzare le variabili di ambiente per cose segrete che cambiano per ciascun server.

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

Come usarli dipende dalla lingua.


3
La sicurezza attraverso l'oscurità non è un approccio raccomandato per molti. Ti andrebbe di elaborare la tua risposta per essere più chiaro?

2
Non è oscurità, le variabili di ambiente sono disponibili solo per l'utente che le hai aggiunte, quindi tutte le tue credenziali hanno la stessa protezione del contesto utente in cui è in esecuzione l'app. Ho aggiornato la risposta per includere il concetto di variabili d'ambiente. È più chiaro?
Filipe Giusti,

4

Penso che questo sia un problema con cui tutti hanno avuto qualche problema ad un certo punto.

Ecco un flusso di lavoro che ho usato, che potrebbe funzionare per te. Usa .gitignore con una svolta:

  1. Tutti i file di configurazione vanno in una cartella speciale (con file di configurazione di esempio - facoltativo)
  2. Tutti i file di configurazione sono inclusi in .gitignore, in modo che non diventino pubblici
  3. Imposta un server gitolite (o il tuo server git preferito) su una casella privata
  4. Aggiungi un repository con tutti i file di configurazione nel server privato
  5. Aggiungi uno script per copiare i file di configurazione nella cartella speciale nel repository principale (opzionale)

Ora puoi clonare il repository di configurazione su qualsiasi sistema di sviluppo e distribuzione. Basta eseguire lo script per copiare i file nella cartella corretta e il gioco è fatto.

Ricevi ancora tutte le caramelle GitHub, condividi il tuo codice con il mondo e i dati sensibili non sono mai nel repository principale, quindi non diventano pubblici. Sono ancora solo un tiro e una copia di distanza da qualsiasi sistema di distribuzione.

Uso una scatola da 15 $ / anno per il server privato git, ma puoi anche installarne uno a casa, secondo il requisito del cheapskate ;-)

PS: potresti anche usare un sottomodulo git ( http://git-scm.com/docs/git-submodule ), ma dimentico sempre i comandi, regole così veloci e sporche!


2

Utilizza la crittografia, ma fornisci una chiave master all'avvio, come password sulla console, in un file che solo l'utente del processo può leggere o da un archivio chiavi fornito dal sistema come il portachiavi Mac OS o l'archivio chiavi di Windows.

Per la consegna continua, ti consigliamo di registrare varie chiavi da qualche parte. La configurazione dovrebbe essere delimitata dal codice, ma ha molto senso tenerlo sotto controllo di revisione.


1

3 strategie, non ancora menzionate (?)

Al check-in o in un gancio di pre-check-in VCS

  • cerca stringhe con elevata entropia, esempio -detect-secrets
  • regex cerca modelli chiave API ben noti. Le chiavi AKIA * di AWS sono un esempio, git-secrets è uno strumento basato su questo. Inoltre, nomi di variabili come "password" con assegnazione costante.
  • cerca segreti conosciuti, conosci i tuoi segreti, cercali nel testo. O usa uno strumento, ho scritto questa prova di concetto .

Strategie già menzionate

  • memorizza nel file al di fuori dell'albero dei sorgenti
  • averlo nell'albero dei sorgenti, ma di 'a VCS di ignorarlo
  • le variabili di ambiente sono una variazione sulla memorizzazione dei dati all'esterno dell'albero di origine
  • semplicemente non dare i preziosi segreti agli sviluppatori

0

Tieni le informazioni private fuori dal controllo del codice sorgente. Crea un valore predefinito non caricato per la distribuzione e fai in modo che il tuo VCS ignori quello reale. Il processo di installazione (manuale, configura / build o procedura guidata) dovrebbe gestire la creazione e il popolamento del nuovo file. Facoltativamente, modificare le autorizzazioni sul file per garantire che solo l'utente richiesto (server web?) Possa leggerlo.

Benefici:

  • Non presuppone un'entità di sviluppo == entità di produzione
  • Non presuppone che tutti i collaboratori / revisori del codice siano affidabili
  • Prevenire errori facili tenendolo fuori dal controllo della versione
  • Installazioni facili da automatizzare con configurazione personalizzata per QA / build

Se lo stai già facendo e lo accedi accidentalmente, aggiungilo a quello del tuo progetto .gitignore. Ciò renderà impossibile farlo di nuovo.

Ci sono molti host Git gratuiti in giro che forniscono repository privati. Anche se non dovresti mai versioni delle tue credenziali, puoi essere economico e avere anche repository privati. ^ _ ^


-2

Invece di avere la chiave OAuth memorizzata come dati non elaborati ovunque, perché non eseguire la stringa tramite un algoritmo di crittografia e archiviarla come hash salato? Quindi utilizzare un file di configurazione per ripristinarlo in fase di esecuzione. In questo modo la chiave non viene archiviata da nessuna parte, sia che si trovi in ​​una casella di sviluppo, sia sul server stesso.

Puoi persino creare un'API in modo tale che il tuo server generi automaticamente una nuova chiave API salata e con hash su una base per richiesta, in questo modo nemmeno il tuo team può vedere l'origine OAuth.

Modifica: Forse prova la Stanford Javascript Crypto Library , consente una crittografia / decrittazione simmetrica abbastanza sicura.


1
Gli hash sono generalmente a senso unico. Esistono algoritmi di crittografia simmetrica che farebbero come suggerisci comunque.

3
Amico, non puoi decodificare (facilmente) un hash. Questo è il punto centrale degli hash. Questo è per ME che consuma l'API di qualcun altro, dove assegnano a ME una chiave segreta. Il mio hashing assicura (a meno che non scelga un algo scadente e lo rompa ogni volta) che non posso usare la loro API.
Will
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.