Strategi untuk menjaga informasi rahasia seperti kunci API di luar kendali sumber?

217

Saya sedang mengerjakan situs web yang akan memungkinkan pengguna untuk masuk menggunakan kredensial OAuth dari orang-orang seperti Twitter, Google, dll. Untuk melakukan ini, saya harus mendaftar dengan berbagai penyedia ini dan mendapatkan kunci API super rahasia yang saya miliki untuk melindungi dengan janji terhadap berbagai bagian tubuh. Jika kunci saya mendapat gank, bagian akan dicabut.

Kunci API harus bepergian dengan sumber saya, karena digunakan saat runtime untuk melakukan permintaan otentikasi. Dalam kasus saya, kunci harus ada dalam aplikasi dalam file konfigurasi atau dalam kode itu sendiri. Itu tidak masalah ketika saya membangun dan menerbitkan dari satu mesin. Namun, ketika kita melempar kontrol sumber ke dalam campuran, semuanya menjadi lebih rumit.

Karena saya bajingan yang murah, saya lebih suka menggunakan layanan kontrol sumber gratis seperti TFS di cloud atau GitHub. Ini membuat saya sedikit bingung:

Bagaimana saya bisa menjaga tubuh saya tetap utuh ketika kunci API saya ada dalam kode saya, dan kode saya tersedia di repositori publik?

Saya dapat memikirkan sejumlah cara untuk menangani hal ini, tetapi tidak satupun yang memuaskan.

  • Saya dapat menghapus semua informasi pribadi dari kode, dan mengeditnya kembali setelah penerapan. Ini akan menjadi sangat sulit untuk diterapkan (saya tidak akan menjelaskan banyak cara), dan bukan pilihan.
  • Saya bisa mengenkripsi itu. Tetapi karena saya harus mendekripsi, siapa pun dengan sumbernya dapat mengetahui bagaimana melakukannya. Tak berarti.
  • Saya bisa membayar untuk kontrol sumber pribadi. LOL j / k menghabiskan uang? Silahkan.
  • Saya dapat menggunakan fitur bahasa untuk memisahkan informasi sensitif dari sumber saya yang lain dan karenanya menjaga dari kontrol sumber. Ini yang saya lakukan sekarang, tetapi bisa dengan mudah dikacaukan dengan memeriksa file rahasia secara keliru.

Saya benar-benar mencari cara yang dijamin untuk memastikan saya tidak membagikan privasi saya dengan dunia (kecuali pada snapchat) yang akan bekerja dengan lancar melalui pengembangan, debugging dan penyebaran dan juga sangat mudah. Ini sama sekali tidak realistis. Jadi apa yang bisa saya lakukan secara realistis?

Detail teknis: VS2012, C # 4.5, kontrol sumber akan menjadi layanan TF atau GitHub. Saat ini menggunakan kelas parsial untuk memisahkan kunci sensitif dalam file .cs terpisah yang tidak akan ditambahkan ke kontrol sumber. Saya pikir GitHub mungkin memiliki keuntungan sebagai .gitignore dapat digunakan untuk memastikan bahwa file kelas parsial tidak diperiksa, tapi saya sudah mengacaukannya sebelumnya. Saya berharap untuk "oh, masalah umum, ini adalah bagaimana Anda melakukannya" tetapi saya mungkin harus puas dengan "yang tidak menyedot sebanyak mungkin",: /

Akan
sumber
6
Anda dapat memastikan, bahwa file konfigurasi yang menyimpan kunci API Anda tidak ada dalam direktori yang dikendalikan sumber, yang akan membuatnya tidak mungkin untuk memeriksanya di tempat pertama.
David Sergey
22
BitBucket.org memiliki repositori pribadi tanpa batas. Gratis. Dan importir repositori gitHub (membuat sejarah)
Rob van der Veer
4
@ Dainius Saya tidak percaya pengembang saya karena saya tahu mereka. Secara intim. Faktanya, aku paling dekat dengan diriku sendiri ... tidak, aku akan membiarkan yang satu berbohong. Tapi saya tahu betapa mudahnya untuk gagal, dan betapa sulitnya untuk menggosok sejarah dari kata screwup.
Will
15
@ Rainius: Ya. Saya melihat setiap karakter kode tim saya. Serius. Saya tidak punya pilihan. Saya tidak bisa kode mata tertutup. Paling tidak tidak bisa diandalkan. Tetapi saya melakukannya, karena saya adalah tim saya. Saya yang di TIM. Ada satu pengembang, dan ini saya. Saya adalah dia. Iya. Saya orang yang akan mengacaukan ini jika dia tidak melakukannya dengan benar. Saya.
Will
3
Mengapa Anda mencoba mengkompilasi kunci ke dalam kode di tempat pertama? Biasa menempatkan hal semacam itu dalam file konfigurasi.
Donal Fellows

Jawaban:

128

Jangan memasukkan informasi rahasia Anda ke dalam kode Anda. Masukkan ke dalam file konfigurasi yang dibaca oleh kode Anda saat startup. File konfigurasi tidak boleh diletakkan di kontrol versi, kecuali mereka adalah "default pabrik", dan kemudian mereka tidak boleh memiliki informasi pribadi.

Lihat juga pertanyaan Kontrol versi dan file konfigurasi pribadi untuk cara melakukannya dengan baik.

Philipp
sumber
8
@RobertHarvey dengan tidak meletakkannya di kontrol versi, menambahkan aturan abaikan bila perlu. Siapa pun yang menggunakan perangkat lunak harus membuat file konfigurasi sendiri dengan kunci API mereka sendiri.
Philipp
10
Jadi, ketika Anda pergi untuk membangun dan membuat distribusi perangkat lunak Anda, bagaimana Anda yakin itu dikirim dengan file konfigurasi? Kecuali Anda memiliki beberapa file dengan standar yang masuk akal, biasanya tidak masuk akal untuk mengharapkan pengguna Anda melalui proses pembuatan file konfigurasi.
Thomas Owens
4
Nah, bawaan pabrik adalah satu bagian, "installer" atau "penyihir pertama kali berjalan" yang lain
johannes
6
Jika banyak pengguna memiliki instalasi sendiri, tidakkah seharusnya mereka membuat dan menggunakan kunci API mereka sendiri? Beberapa situs / instal menggunakan kunci yang sama mungkin merupakan ide yang buruk. Jika hanya satu instal, maka menggunakan file konfigurasi bukanlah masalah besar.
Mike Weller
10
@ Akan, jika Anda tidak dapat melakukan ini karena tidak praktisnya detail implementasi, maka saya akan mengatakan Anda tidak memiliki alat yang tepat untuk penyebaran. Penempatan menggunakan file konfigurasi rahasia yang tidak dikomit harus sepenuhnya tidak menyakitkan. Saya tidak dapat menawarkan saran khusus kepada Anda karena saya tinggal di ekosistem Ruby, bukan C #. Tetapi orang-orang Ruby cenderung menggunakan Capistrano untuk penyebaran otomatis. Saya yakin C # memiliki alat untuk penyebaran otomatis juga, dan ini akan membuat prosesnya mudah.
Ben Lee
29

Anda bisa meletakkan semua kunci privat / terlindungi sebagai variabel lingkungan sistem. File konfigurasi Anda akan terlihat seperti ini:

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

Inilah cara kami menangani kasus-kasus itu dan tidak ada yang masuk ke dalam kode. Ini bekerja sangat baik dikombinasikan dengan file dan profil properti yang berbeda. Kami menggunakan file properti yang berbeda untuk lingkungan yang berbeda. Di lingkungan pengembangan lokal kami, kami meletakkan kunci pengembangan di file properti untuk menyederhanakan pengaturan lokal:

private.key=A_DEVELOPMENT_LONG_KEY
Ioannis Tzikas
sumber
Ini akan menjadi solusi yang masuk akal jika saya bisa membuatnya bekerja dengan opsi hosting saya. Tidak akan menjadi variabel lingkungan, tetapi mungkin beberapa pasangan konfigurasi kunci / nilai yang tidak terhapus setelah penerbitan ...
Will
Bagaimana dengan menempatkan variabel lingkungan tersebut di server build Anda sebelum dikirim ke lingkungan langsung? Dengan begitu Anda akan siap untuk file sumber daya / konfigurasi.
Ioannis Tzikas
Server build adalah mesin pengembangan, itulah sebabnya saya khawatir tentang info ini yang mungkin diperiksa secara tidak sengaja ke kontrol sumber.
Will
Masalah dengan ini mungkin karena lingkungan dapat dibaca oleh siapa saja di server.
JasonG
Envvars pengguna hanya dapat dibaca oleh pengguna atau root. (Linux Kuno dan AIX tidak melakukan ini)
Neil McGuigan
27

Cara Git murni

  • .gitignore termasuk file dengan data pribadi
  • Gunakan cabang lokal, di mana Anda mengganti TEMPLATEdenganDATA
  • Gunakan filter noda / bersih, di mana skrip filter (lokal) melakukan penggantian dua arah TEMPLATE<->DATA

Cara lincah

  • MQ-patch (es) di atas kode dummy, yang diganti TEMPLATEdengan DATA(perubahan bersifat publik, patch bersifat pribadi)
  • Ekstensi kata kunci dengan kata kunci yang dirancang khusus (hanya diperluas di direktori kerja Anda )

Cara SCM-agnostik

  • Memiliki penggantian kata kunci sebagai bagian dari proses build / deploy
Malas Badger
sumber
Hmmm ... Saran git itu baik, dan saran agnostik Anda memberi saya ide yang bagus ... Saya bisa menggunakan build events untuk memperkenalkan file ke dalam proses penerbitan, kemudian menghapusnya setelah itu, sehingga membantu memastikan bahwa itu tidak akan secara tidak sengaja ditambahkan ke kontrol sumber ..
Will
7
Tidak, tidak, dan sekali lagi - tidak! mengabaikan file bagus untuk menambahkan beberapa kustomisasi yang sangat spesifik untuk membangun proses atau sesuatu, tetapi itu tidak boleh digunakan untuk menyimpan data aman apa pun. Jangan menyimpan data aman dalam repo, bahkan jika Anda mengabaikannya.
shabunc
11
@shabunc - RTFM! File yang diabaikan tidak disimpan dalam repo
Lazy Badger
9
@ LazyBadger - Saya tahu betul itu diabaikan. Saya juga tahu bahwa, dalam repo, SELALU ada kesempatan bahwa seseorang bagaimanapun juga akan menambahkannya entah bagaimana ke repo. Beberapa jalur konfigurasi eksternal jauh lebih baik.
shabunc
4
@shabunc - poin bagus untuk menjaga konfigurasi dari jalur SCM. Inilah sebabnya, misalnya, Postgres memungkinkan Anda memintas pemeriksaan kata sandi dengan memasukkan kata sandi ke dalam file. Tetapi mereka mengharuskan file kata sandi diletakkan di ~ / .pgpass - yang mungkin bukan lokasi yang sangat nyaman untuk memeriksa ke dalam kontrol sumber. Mereka tahu, untuk otomatisasi, mereka harus memberi Anda senjata, tetapi mereka bekerja keras untuk mencegah Anda menembak kaki Anda dengan itu ..
Steve Midgley
14

Saya menaruh rahasia ke file terenkripsi yang kemudian saya komit. Frasa pass diberikan ketika sistem diluncurkan, atau disimpan dalam file kecil yang tidak saya komit. Sangat menyenangkan bahwa Emacs akan dengan riang mengelola file-file terenkripsi ini. Sebagai contoh, file inac emacs termasuk: (memuat "secrets.el.gpg"), yang hanya berfungsi - meminta saya untuk memasukkan kata sandi pada kesempatan langka ketika saya memulai editor. Saya tidak khawatir tentang seseorang yang melanggar enkripsi.

Ben Hyde
sumber
3
Ini adalah solusi yang bagus - Saya terkejut Anda tidak memiliki lebih banyak suara. Saya bekerja dengan perusahaan yang menangani data siswa, yang diatur secara federal di AS, sehingga mereka harus ekstra hati-hati dengan kredensial dan rahasia. Mereka juga adalah perusahaan besar sehingga mereka perlu menggunakan SCM untuk kredensial sehingga TI dapat menemukan / mengelolanya setelah mereka membangunnya. Solusi Anda persis seperti apa yang mereka lakukan. Mereka memiliki file kunci dekripsi yang menyimpan kunci dekripsi untuk dev / staging / prod / etc (satu file untuk masing-masing). Kemudian semua rahasia dienkripsi dan diperiksa ke dalam file. File dekripsi digunakan untuk mendapatkannya di setiap lingkungan.
Steve Midgley
7
Nah, dalam beberapa hal mengenkripsi rahasia (kunci API dalam kasus ini) hanya menggeser masalah dari tidak melakukan data rahasia menjadi tidak melakukan frase sandi (yang sekarang menjadi data rahasia ). Tapi tentu saja, memintanya saat peluncuran sistem adalah pilihan yang baik.
siegi
Saya suka solusi ini. Jenis file terenkripsi yang Anda komit bisa berupa file KeePass. Itu akan memiliki entri untuk setiap lingkungan, menggunakan notesbidang untuk menyimpan konten file .env. Beberapa bulan yang lalu saya menulis alat yang dapat membaca file keepass dan membuat file .env menggunakan notesbidang entri. Saya sedang berpikir untuk menambahkan fitur sehingga saya bisa melakukan require('switchenv').env()di bagian atas program Node.js dan membuat variabel process.env berdasarkan entri yang cocok dengan NODE_ENV atau sesuatu seperti itu. -> github.com/christiaanwesterbeek/switchenv
Christiaan Westerbeek
14

Ini sangat spesifik untuk Android / Gradle tetapi Anda dapat menentukan kunci di gradle.propertiesfile global Anda yang terletak di user home/.gradle/. Ini juga berguna karena Anda dapat menggunakan properti yang berbeda tergantung pada buildType atau rasa yaitu API untuk dev dan yang berbeda untuk rilis.

properti

MY_PRIVATE_API_KEY=12356abcefg

build.gradle

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

Dalam kode Anda akan referensi seperti ini

String myAPI = BuildConfig.GOOGLE_VERIFICATION_API_KEY;
scottyab
sumber
BuildConfig diterjemahkan ke file sumber yang sesuai, sehingga rekayasa balik yang sederhana di apk Anda akan mengungkapkan semua kunci dan rahasia yang Anda masukkan ke dalam BuildConfig
Dmitri Livotov
1
Memang poin yang valid. Tetapi pertanyaannya adalah tentang bagaimana menjaga kunci api dari kode sumber bukan biner.
scottyab
11

Anda tidak seharusnya mendistribusikan kunci itu dengan aplikasi Anda atau menyimpannya di repositori kode sumber. Pertanyaan ini menanyakan bagaimana melakukan itu, dan bukan itu yang biasanya dilakukan.

Aplikasi Web Seluler

Untuk Android / iPhone perangkat harus meminta KUNCI dari layanan web Anda sendiri ketika aplikasi pertama kali dijalankan. Kunci tersebut kemudian disimpan di lokasi yang aman. Haruskah kunci diubah atau dicabut oleh penerbit. Layanan web Anda dapat menerbitkan kunci baru.

Aplikasi Web yang Diinangi

Pelanggan yang menggunakan lisensi perangkat lunak Anda harus memasukkan kunci secara manual saat pertama kali mengkonfigurasi perangkat lunak. Anda dapat memberi semua orang kunci yang sama, kunci yang berbeda atau mereka mendapatkan kunci mereka sendiri.

Kode Sumber yang Diterbitkan

Anda menyimpan kode sumber Anda di repositori publik tetapi bukan KUNCI. Dalam konfigurasi file, Anda menambahkan baris * tombol tempat di sini * . Ketika seorang pengembang menggunakan kode sumber Anda, mereka membuat salinan sample.cfgfile dan menambahkan kunci mereka sendiri.

Anda tidak menyimpan config.cfgfile Anda digunakan untuk pengembangan atau produksi di repositori.

Reactgular
sumber
4
Pertanyaan ini menanyakan bagaimana melakukan itu tidak, itu sama sekali TIDAK. Faktanya adalah bahwa kunci-kunci ini perlu digunakan oleh kode, oleh karena itu dapat diakses oleh kode, dan itu biasanya berarti melalui kode atau file konfigurasi, yang jika mereka tidak dalam sumber bersama-sama mereka setidaknya dekat dan mungkin secara tidak sengaja berakhir di sumber. Sayangnya, aplikasi web yang dihosting tidak masuk akal. Anda tidak perlu mengajukan kunci api untuk masuk ke StackOverflow melalui akun facebook Anda (hipotetis). kunci tempat di sini adalah penyederhanaan besar-besaran yang tidak akan berfungsi di lingkungan pub seperti yang dijelaskan dalam Q.
Will
Saya telah menjawab pertanyaan dengan benar, seperti banyak pertanyaan lainnya. Fakta bahwa Anda belum menerima salah satu dari mereka menyiratkan Anda tidak mengerti cara bekerja dengan kunci-kunci ini.
Reactgular
7
Lalu bagaimana kita melindungi layanan web penerbitan kunci? Menggunakan kunci lain?
Jiangge Zhang
Ditto apa yang dikatakan @JianggeZhang - ini adalah saran berbahaya
David K. Hess
5

Gunakan variabel lingkungan untuk hal-hal rahasia yang berubah untuk setiap server.

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

Cara menggunakannya bergantung pada bahasa.

Filipe Giusti
sumber
3
Keamanan melalui ketidakjelasan bukanlah pendekatan yang disarankan bagi banyak orang. Apakah Anda ingin menjelaskan jawaban Anda menjadi lebih jelas?
2
Itu tidak jelas, variabel lingkungan hanya tersedia untuk pengguna yang Anda tambahkan, sehingga semua kredensial Anda memiliki perlindungan yang sama dari konteks pengguna yang sedang dijalankan aplikasi Anda. Saya memperbarui jawaban untuk memasukkan konsep variabel lingkungan. Apakah itu lebih jelas?
Filipe Giusti
4

Saya pikir ini adalah masalah yang setiap orang punya masalah pada suatu saat.

Inilah alur kerja yang telah saya gunakan, yang mungkin cocok untuk Anda. Ini menggunakan .gitignore dengan twist:

  1. Semua file konfigurasi masuk dalam folder khusus (dengan file konfigurasi sampel - opsional)
  2. Semua file konfigurasi termasuk dalam .gitignore, sehingga tidak go public
  3. Atur server gitolite (atau server git favorit Anda) pada kotak pribadi
  4. Tambahkan repo dengan semua file konfigurasi di server pribadi
  5. Tambahkan skrip untuk menyalin file konfigurasi ke folder khusus di repo utama (opsional)

Sekarang, Anda dapat mengkloning konfigurasi repo ke sistem pengembangan dan penyebaran apa pun. Cukup jalankan skrip untuk menyalin file ke folder yang benar dan Anda selesai.

Anda masih mendapatkan semua permen GitHub, membagikan kode Anda dengan dunia dan data sensitif tidak pernah ada dalam repo utama, sehingga mereka tidak go public. Mereka masih hanya tarikan dan salinan dari sistem penyebaran apa pun.

Saya menggunakan kotak $ 15 / tahun untuk server private git, tetapi Anda juga dapat mengaturnya di rumah, sesuai persyaratan pelit ;-)

PS: Anda juga bisa menggunakan submitule git ( http://git-scm.com/docs/git-submodule ), tetapi saya selalu lupa perintahnya, aturannya begitu cepat & kotor!

Kostas
sumber
2

Gunakan enkripsi, tetapi berikan kunci utama saat startup, sebagai kata sandi di konsol, dalam file yang hanya dapat dibaca oleh pengguna, atau dari penyimpanan kunci yang disediakan sistem seperti gantungan kunci Mac OS atau penyimpanan kunci Windows.

Untuk pengiriman terus-menerus, Anda ingin berbagai kunci direkam di suatu tempat. Konfigurasi harus dibatasi dari kode, tetapi masuk akal untuk menyimpannya di bawah kendali revisi.

erickson
sumber
1

3 Strategi, belum disebutkan (?)

Saat check-in atau dalam kait pra-cek VCS

  • mencari string dengan entropi tinggi, contoh -deteksi-rahasia
  • pencarian regex untuk pola kunci API yang terkenal. Kunci AKIA * AWS adalah contohnya, git-secrets adalah salah satu alat berdasarkan itu. Juga, nama variabel seperti 'kata sandi' dengan tugas konstan.
  • mencari rahasia yang diketahui - Anda tahu rahasia Anda, cari teks untuk mereka. Atau gunakan alat, saya menulis bukti konsep ini .

Strategi sudah disebutkan

  • simpan dalam file di luar pohon sumber
  • memilikinya di pohon sumber, tetapi katakan VCS untuk mengabaikannya
  • variabel lingkungan adalah variasi dalam menyimpan data di luar pohon sumber
  • Hanya saja, jangan memberikan rahasia berharga kepada pengembang
MatthewMartin
sumber
0

Jauhkan informasi pribadi dari kendali sumber Anda. Buat default yang tidak dimuat untuk distribusi, dan biarkan VCS Anda mengabaikan yang asli. Proses instalasi Anda (apakah manual, configure / build atau wizard) harus menangani membuat dan mengisi file baru. Secara opsional memodifikasi izin pada file untuk memastikan hanya pengguna yang diperlukan (server web?) Yang dapat membacanya.

Manfaat:

  • Tidak menganggap entitas pengembangan == entitas produksi
  • Tidak menganggap semua kolaborator / peninjau kode dipercaya
  • Cegah kesalahan mudah dengan menjaganya dari kontrol versi
  • Instalasi otomatis mudah dengan konfigurasi khusus untuk QA / build

Jika Anda sudah melakukan ini dan secara tidak sengaja memeriksanya, tambahkan ke proyek Anda .gitignore. Ini akan membuat tidak mungkin dilakukan lagi.

Ada yang banyak Git host gratis di sekitar yang menyediakan repositori pribadi. Meskipun Anda seharusnya tidak pernah versi kredensial Anda, Anda bisa murah dan memiliki repo pribadi juga. ^ _ ^

Adrian Schneider
sumber
-2

Alih-alih menyimpan kunci OAuth sebagai data mentah di mana saja, mengapa tidak menjalankan string melalui beberapa algoritma enkripsi, dan menyimpannya sebagai hash asin? Kemudian gunakan file konfigurasi untuk mengembalikannya saat runtime. Dengan begitu kunci tidak disimpan di mana pun, apakah disimpan di kotak pengembangan, atau server itu sendiri.

Anda bahkan dapat membuat API sedemikian rupa sehingga server Anda secara otomatis menghasilkan kunci API asin dan hash baru berdasarkan permintaan, sehingga tidak ada tim Anda yang dapat melihat sumber OAuth.

Sunting: Mungkin mencoba Stanford Javascript Crypto Library , memungkinkan beberapa enkripsi / dekripsi simetris yang cukup aman.

David Freitag
sumber
1
Hash umumnya mengacak satu arah. Ada algoritma enkripsi simetris yang akan melakukan seperti yang Anda sarankan.
3
Sobat, kamu tidak bisa tidak mengenkripsi (dengan mudah) sebuah hash. Itulah inti hash. Ini untukKU yang mengkonsumsi API orang lain, di mana mereka memberi saya kunci rahasia. Hash saya memastikan (kecuali saya memilih algo yang buruk dan memecahkannya setiap waktu) bahwa saya tidak dapat menggunakan API mereka.
Will