Estratégia para manter informações secretas, como chaves de API, fora do controle de origem?

217

Estou trabalhando em um site que permitirá que os usuários efetuem login usando credenciais OAuth de sites como o Twitter, Google etc. Para fazer isso, preciso me registrar com esses vários provedores e obter uma chave API secreta que possuo para proteger com promessas contra várias partes do corpo. Se minha chave for arrancada, a parte será puxada.

A chave da API precisa viajar com a minha fonte, pois é usada em tempo de execução para executar solicitações de autenticação. No meu caso, a chave deve existir no aplicativo em um arquivo de configuração ou no próprio código. Isso não é um problema quando eu construo e publico a partir de uma única máquina. No entanto, quando colocamos o controle de origem na mistura, as coisas ficam mais complicadas.

Como sou um bastardo barato, prefiro usar serviços de controle de fonte gratuitos, como o TFS na nuvem ou o GitHub. Isso me deixa com um pequeno enigma:

Como posso manter meu corpo intacto quando minhas chaves de API estão no meu código e meu código está disponível em um repositório público?

Posso pensar em várias maneiras de lidar com isso, mas nenhuma delas é tão satisfatória.

  • Eu poderia remover todas as informações particulares do código e editá-las novamente após a implantação. Isso seria muito difícil de implementar (não detalharei as várias maneiras) e não é uma opção.
  • Eu poderia criptografá-lo. Mas como eu tenho que decifrá-lo, qualquer pessoa com a fonte pode descobrir como fazê-lo. Sem sentido.
  • Eu poderia pagar pelo controle de fontes privadas. LOL j / k gasta dinheiro? Por favor.
  • Eu poderia usar os recursos de idioma para separar informações confidenciais do restante da minha fonte e, portanto, mantê-las fora do controle da fonte. É isso que estou fazendo agora, mas pode ser facilmente estragado ao checar por engano o arquivo secreto.

Estou realmente procurando uma maneira garantida de garantir que não compartilhe meus interesses com o mundo (exceto no snapchat), que funcionará sem problemas durante o desenvolvimento, a depuração e a implantação, além de ser à prova de falhas. Isso é completamente irreal. Então, o que realisticamente eu posso fazer?

Detalhes técnicos: VS2012, C # 4.5, o controle de origem será serviço TF ou GitHub. Atualmente, está usando uma classe parcial para dividir as chaves confidenciais em um arquivo .cs separado que não será adicionado ao controle de origem. Acho que o GitHub pode ter a vantagem, pois o .gitignore pode ser usado para garantir que o arquivo de classe parcial não seja verificado, mas eu estraguei tudo isso antes. Estou esperando por um "oh, problema comum, é assim que você faz", mas talvez eu tenha que me contentar com "que não é tão ruim quanto poderia",: /

Vai
fonte
6
Você pode ter certeza de que o arquivo de configuração que contém sua chave de API não está no diretório controlado de origem, o que tornará impossível fazer o check-in em primeiro lugar.
David Sergey
22
BitBucket.org tem repositórios privados ilimitados. Livre. E GitHub importador de repositório (mantém a história)
Rob van der Veer
4
@ Dainius Não confio nos meus desenvolvedores porque os conheço. Intimamente. Na verdade, sou íntimo de mim mesmo, pelo menos ... não, vou deixar isso mentir. Mas eu sei como é fácil estragar tudo e quão difícil será esfoliar o histórico desse estrago.
Will
15
@ Dainius: Sim. Eu olho para cada personagem que meu time codifica. A sério. Eu não tenho escolha. Não consigo codificar com os olhos vendados. Não é confiável, pelo menos. Mas sim, porque sou meu time. Eu sou o eu da equipe. Há um desenvolvedor e sou eu. Eu sou ele Sim. Eu sou o cara que vai estragar tudo se ele não fizer isso direito. Eu.
Will
3
Por que você está tentando compilar a chave no código em primeiro lugar? É comum colocar esse tipo de coisa em um arquivo de configuração.
Donal Fellows

Respostas:

128

Não coloque suas informações secretas no seu código. Coloque-o em um arquivo de configuração que é lido pelo seu código na inicialização. Os arquivos de configuração não devem ser colocados no controle de versão, a menos que sejam os "padrões de fábrica" ​​e não tenham informações particulares.

Consulte também a pergunta Controle de versão e arquivo de configuração pessoal para saber como fazer isso bem.

Philipp
fonte
8
@RobertHarvey, simplesmente não colocando-o no controle de versão, adicionando uma regra de ignorar quando necessário. Qualquer pessoa que utilize o software precisará criar seu próprio arquivo de configuração com sua própria chave de API.
Philipp
10
Então, quando você cria e distribui seu software, como tem certeza de que ele é fornecido com um arquivo de configuração? A menos que você tenha algum arquivo com padrões razoáveis, geralmente não é razoável esperar que seu usuário passe por um processo de criação de um arquivo de configuração.
Thomas Owens
4
Bem, os padrões de fábrica são uma parte, "instaladores" ou "primeiros assistentes correr" mais um
Johannes
6
Se muitos usuários tiverem sua própria instalação, eles não devem criar e usar sua própria chave de API? Vários sites / instalações usando a mesma chave provavelmente são uma má idéia. Se for apenas uma instalação, usar um arquivo de configuração não é um grande aborrecimento.
22613 Mike Weller
10
@ Se você não puder fazer isso por causa da impraticabilidade dos detalhes de implementação, diria que você simplesmente não possui as ferramentas adequadas para implantação. A implantação usando um arquivo de configuração secreto não confirmado deve ser completamente indolor. Não posso oferecer conselhos específicos para você, pois vivo no ecossistema Ruby, não em C #. Mas o pessoal do Ruby costuma usar o Capistrano para implantações automatizadas. Tenho certeza de que o C # também possui sua ferramenta para implantação automatizada, e isso deve facilitar o processo.
Ben Lee
29

Você pode colocar todas as chaves privadas / protegidas como variáveis ​​de ambiente do sistema. Seu arquivo de configuração ficará assim:

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

É assim que lidamos com esses casos e nada entra em código. Funciona muito bem combinado com diferentes arquivos e perfis de propriedades. Usamos arquivos de propriedades diferentes para diferentes ambientes. Em nosso ambiente de desenvolvimento local, colocamos as chaves de desenvolvimento nos arquivos de propriedades para simplificar a configuração local:

private.key=A_DEVELOPMENT_LONG_KEY
Ioannis Tzikas
fonte
Essa seria uma solução razoável se eu conseguir fazê-lo funcionar com minha opção de hospedagem. Não será variáveis de ambiente, mas talvez alguns pares de configuração de chave / valor que não são eliminados depois de publicar ...
Will
Que tal colocar essas variáveis ​​de ambiente no servidor de compilação antes de enviar para o ambiente ativo? Dessa forma, você estará pronto para os arquivos de recursos / configuração de produção.
Ioannis Tzikas
O servidor de compilação é a máquina de desenvolvimento, e é por isso que estou preocupado com a possibilidade de essas informações serem checadas acidentalmente no controle de origem.
Will
O problema com isso pode ser que o ambiente seja legível por qualquer pessoa no servidor.
JasonG
Os envvars de um usuário são legíveis apenas pelo usuário ou raiz. (Ancient Linux e AIX não fazer isso no entanto)
Neil McGuigan
27

Maneira pura Git

  • .gitignore arquivo incluído com dados privados
  • Use uma filial local, na qual você substitui TEMPLATEporDATA
  • Use filtros de borrar / limpar, nos quais o script do filtro (local) executa a substituição bidirecional TEMPLATE<->DATA

Maneira mercurial

  • MQ-patch (s) sobre o código fictício, que substitui TEMPLATEpor DATA(changesets são públicos, patch é privado)
  • Extensão de palavra-chave com palavras-chave especialmente projetadas (expandida apenas em seu diretório de trabalho )

Maneira agnóstica de SCM

  • Ter a substituição de palavras-chave como parte do processo de criação / implantação
Lazy Badger
fonte
Hmmm ... O conselho do git é bom, e o seu conselho agnóstico me dá uma boa idéia ... Eu posso usar os eventos de compilação para introduzir o arquivo no processo de publicação e removê-lo depois, ajudando assim a garantir que ele não acidentalmente ser adicionado ao controle de origem ..
Will
7
Não, não e mais uma vez - não! ignorar arquivos é bom para adicionar alguma personalização muito específica para criar processo ou algo assim, mas nunca deve ser usado para armazenar dados seguros. Não armazene dados seguros no repositório, mesmo se você os estiver ignorando.
23613 shabunc
11
@shabunc - RTFM! Arquivo ignorado não armazenados em repo
preguiçoso Badger
9
@ LazyBadger - eu sei muito bem que é ignorado. Sei também que, estando em repo, sempre existe a chance de alguém, por engano, adicioná-lo de alguma forma ao repo. Algum caminho de configuração externa é muito melhor.
shabunc
4
@shabunc - bom ponto de manter a configuração fora do caminho do SCM. É por isso que, por exemplo, o Postgres permite ignorar as verificações de senha, colocando a senha em um arquivo. Mas eles exigem que o arquivo de senha seja colocado em ~ / .pgpass - o que provavelmente não é um local muito conveniente para verificar o controle de origem. Eles sabem que, para automação, eles têm que dar-lhe uma arma, mas eles trabalham duro para mantê-lo de tiro no próprio pé com ele ..
Steve Midgley
14

Eu coloquei segredos em arquivos criptografados que eu confirmo. A frase secreta é fornecida quando o sistema é iniciado ou é armazenada em um arquivo pequeno que eu não confirmo. É bom que o Emacs gerencie alegremente esses arquivos criptografados. Por exemplo, o arquivo init do emacs inclui: (load "secrets.el.gpg"), que simplesmente funciona - solicitando a senha nessas raras ocasiões quando inicio o editor. Não me preocupo com alguém quebrando a criptografia.

Ben Hyde
fonte
3
Esta é uma ótima solução - estou surpreso por você não ter mais votos. Eu trabalho com uma empresa que lida com dados de estudantes, regulamentada federalmente nos EUA, para que eles tenham um cuidado extra com credenciais e segredos. Eles também são uma grande empresa e, portanto, precisam usar o SCM para credenciais, para que a TI possa encontrá-los / gerenciá-los depois que o engr os constrói. Sua solução é exatamente o que eles fazem. Eles descriptografaram arquivos de chaves que contêm chaves descriptografadas para dev / staging / prod / etc (um arquivo para cada). Todos os segredos são criptografados e verificados em arquivos. Os arquivos de descriptografia são usados ​​para obtê-los em cada ambiente.
Steve Midgley
7
Bem, de certa forma, criptografar o segredo (chave da API nesse caso) apenas muda o problema de não confirmar os dados secretos para não confirmar a senha (que agora se torna os dados secretos ). Mas é claro que solicitá-lo no lançamento do sistema é uma boa opção.
Siegi
Eu gosto desta solução. O tipo de arquivo criptografado que você confirma pode ser um arquivo KeePass. Teria uma entrada para cada ambiente, usando o notescampo para armazenar o conteúdo do arquivo .env. Alguns meses atrás, escrevi uma ferramenta que pode ler um arquivo keepass e criar um arquivo .env usando o notescampo de uma entrada. Estou pensando em adicionar um recurso para que eu possa fazer require('switchenv').env()no topo do programa Node.js. e criar variáveis ​​process.env com base na entrada que corresponde a NODE_ENV ou algo assim. -> github.com/christiaanwesterbeek/switchenv
Christiaan Westerbeek
14

Isso é muito específico para Android / Gradle, mas você pode definir as chaves no seu gradle.propertiesarquivo global localizado em user home/.gradle/. Isso também é útil, pois você pode usar propriedades diferentes, dependendo do buildType ou do sabor, isto é, API para dev e uma diferente para release.

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

No código que você referencia assim

String myAPI = BuildConfig.GOOGLE_VERIFICATION_API_KEY;
scottyab
fonte
BuildConfig traduz para o arquivo-fonte correspondente, engenharia reversa tão simples em seu apk irá revelar todas as chaves e segredos que você colocou no BuildConfig
Dmitri Livotov
11
De fato, um ponto válido. Mas a questão era sobre como manter as chaves da API fora do código-fonte e não do binário.
scottyab
11

Você não deve distribuir essa chave com seu aplicativo ou armazená-la no repositório de código-fonte. Esta pergunta está perguntando como fazer isso, e isso não é o que normalmente é feito.

Aplicativo da Web para celular

Para Android / iPhone, o dispositivo deve solicitar a CHAVE do seu próprio serviço da web quando o aplicativo é executado pela primeira vez. A chave é então armazenada em um local seguro. A chave deve ser alterada ou revogada pelo editor. Seu serviço da web pode publicar uma nova chave.

Aplicativo da Web hospedado

Os clientes que usam uma licença do seu software precisarão inserir a chave manualmente na primeira configuração do software. Você pode dar a todos a mesma chave, chaves diferentes ou elas terão as suas próprias.

Código-fonte publicado

Você armazena seu código-fonte em um repositório público, mas não na KEY. Na configuração do arquivo, você adiciona as linhas * coloque a chave aqui * . Quando um desenvolvedor usa seu código-fonte, ele faz uma cópia do sample.cfgarquivo e adiciona sua própria chave.

Você não mantém seu config.cfgarquivo usado para desenvolvimento ou produção no repositório.

Reactgular
fonte
4
Esta pergunta está perguntando como fazer isso não, absolutamente NÃO. O fato é que essas chaves precisam ser usadas pelo código, portanto, acessadas pelo código, e isso geralmente significa via código ou arquivos de configuração, que, se não estiverem na fonte juntos, estão pelo menos próximos e podem acabar acidentalmente em fonte. O aplicativo da web hospedado é absurdo, infelizmente. Você não precisou solicitar uma chave API para fazer login no StackOverflow por meio da sua conta do Facebook (hipotética). chave lugar aqui é uma simplificação enorme que não vai funcionar em dev-> ambientes pub como é descrito no Q.
Will
Eu respondi a pergunta corretamente, assim como muitas outras. O fato de você não ter aceito um deles implica que você não entende como trabalhar com essas chaves.
Reactgular 23/07
7
Então, como protegemos o serviço da Web de publicação de chaves? Usando outra chave?
Jiangge Zhang
Ditto que @JianggeZhang disse - este é um conselho perigoso
David K. Hess
5

Use variáveis ​​de ambiente para coisas secretas que mudam para cada servidor.

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

Como usá-los depende do idioma.

Filipe Giusti
fonte
3
A segurança através da obscuridade não é uma abordagem recomendada para muitos. Você gostaria de elaborar sua resposta para ser mais claro?
2
Isso não é obscuridade, as variáveis ​​de ambiente estão disponíveis apenas para o usuário que você adicionou, portanto todas as suas credenciais têm a mesma proteção do contexto do usuário que seu aplicativo está executando. Atualizei a resposta para incluir o conceito de variáveis ​​de ambiente. Isso é mais claro?
Filipe Giusti
4

Acho que esse é um problema com o qual todos já tiveram problemas em algum momento.

Aqui está um fluxo de trabalho que usei, que pode funcionar para você. Ele usa .gitignore com um toque:

  1. Todos os arquivos de configuração vão para uma pasta especial (com arquivos de configuração de amostra - opcional)
  2. Todos os arquivos de configuração são incluídos no .gitignore, para que não sejam públicos
  3. Configure um servidor gitolite (ou seu servidor git favorito) em uma caixa particular
  4. Adicione um repositório com todos os arquivos de configuração no servidor privado
  5. Adicione um script para copiar arquivos de configuração para a pasta especial no repositório principal (opcional)

Agora, você pode clonar o repositório de configuração para qualquer sistema de desenvolvimento e implantação. Basta executar o script para copiar os arquivos para a pasta correta e pronto.

Você ainda recebe todos os doces do GitHub, compartilha seu código com o mundo e os dados confidenciais nunca estão no repositório principal, para que eles não sejam públicos. Eles ainda estão apenas a um pull e a uma cópia de qualquer sistema de implantação.

Eu uso uma caixa de 15 $ / ano para o servidor git privado, mas você também pode configurar uma em casa, de acordo com o requisito;

PS: Você também pode usar um sub-módulo git ( http://git-scm.com/docs/git-submodule ), mas eu sempre esqueço os comandos, regras tão rápidas e sujas!

Kostas
fonte
2

Use criptografia, mas forneça uma chave mestra na inicialização, como uma senha no console, em um arquivo que apenas o usuário do processo possa ler ou em um armazenamento de chaves fornecido pelo sistema, como o chaveiro do Mac OS ou o chaveiro do Windows.

Para entrega contínua, você desejará várias chaves gravadas em algum lugar. A configuração deve ser demarcada do código, mas faz muito sentido mantê-la sob controle de revisão.

erickson
fonte
1

3 Estratégias ainda não mencionadas (?)

No check-in ou no gancho de pré-check-in do VCS

  • procure seqüências com alta entropia, exemplo - detectar segredos
  • regex procura por padrões de chave de API conhecidos. As chaves AKIA * da AWS são um exemplo, o git-secrets é uma ferramenta baseada nisso. Além disso, nomes de variáveis ​​como 'senha' com atribuição constante.
  • procure segredos conhecidos - você conhece seus segredos, procure texto por eles. Ou use uma ferramenta, escrevi essa prova de conceito .

Estratégias já mencionadas

  • armazenar no arquivo fora da árvore de origem
  • tê-lo na árvore de origem, mas diga ao VCS para ignorá-lo
  • variáveis ​​de ambiente são uma variação no armazenamento de dados fora da árvore de origem
  • apenas não dê os segredos valiosos para os desenvolvedores
MatthewMartin
fonte
0

Mantenha as informações privadas fora do seu controle de origem. Crie um padrão não carregado para distribuição e faça com que seu VCS ignore o real. O processo de instalação (manual, de configuração / compilação ou assistente) deve lidar com a criação e o preenchimento do novo arquivo. Opcionalmente, modifique as permissões no arquivo para garantir que apenas o usuário necessário (servidor da web?) Possa lê-lo.

Benefícios:

  • Não assume entidade de desenvolvimento == entidade de produção
  • Não assume que todos os colaboradores / revisores de código são confiáveis
  • Evite erros fáceis, mantendo-o fora do controle de versão
  • Fácil de automatizar instalações com configuração personalizada para controle de qualidade / compilações

Se você já está fazendo isso e está fazendo check-in acidentalmente, adicione-o ao seu projeto .gitignore. Isso tornará impossível fazer novamente.

Não são abundância de hospedeiros Git livres ao redor que fornecem repositórios privados. Embora você nunca deva versão suas credenciais, você pode ser barato e ter acordos privados também. ^ _ ^

Adrian Schneider
fonte
-2

Em vez de ter a chave OAuth armazenada como dados brutos em qualquer lugar, por que não executar a string através de algum algoritmo de criptografia e armazená-la como um hash salgado? Em seguida, use um arquivo de configuração para restaurá-lo em tempo de execução. Dessa forma, a chave não é armazenada em nenhum lugar, seja em uma caixa de desenvolvimento ou no próprio servidor.

Você pode até criar uma API para que seu servidor gere automaticamente uma nova chave de API salgada e com hash por solicitação, para que nem sua equipe possa ver a fonte do OAuth.

Edit: Talvez tente a Stanford Javascript Crypto Library , ela permite criptografia / descriptografia simétrica bastante segura.

David Freitag
fonte
11
Hashes são geralmente uma maneira de embaralhar. Existem algoritmos de criptografia simétrica que poderiam ser os que você sugere.
3
Cara, você não pode descriptografar (facilmente) um hash. Esse é o ponto principal dos hashes. Isso é para ME consumindo a API de outra pessoa, onde eles atribuem a ME uma chave secreta. Meu hash garante (a menos que eu escolha um algo ruim e decifre toda vez) que não posso usar a API deles.
Will