Bagaimana cara melindungi nama pengguna dan kata sandi MySQL agar tidak terurai?

87

.classFile Java dapat didekompilasi dengan cukup mudah. Bagaimana cara melindungi database saya jika saya harus menggunakan data login dalam kode?

Jakob Cosoroaba
sumber
Saya harap Anda tidak keberatan saya memberi tag ulang pada pertanyaan Anda. Saya menghapus "username" dan "password" dan menambahkan "reverse-engineering" dan "decompiling". Saya pikir mereka lebih deskriptif daripada aslinya. Pertanyaan bagus tentang fundamental, ngomong-ngomong!
William Brendel
6
Perhatikan bahwa fakta bahwa Anda menggunakan Java tidak benar-benar relevan di sini. Memiliki kata sandi yang di-hardcode dalam bahasa apa pun juga bermasalah dengan cara yang hampir sama ("string biner" juga menunjukkan konstanta string dalam program C).
Joachim Sauer
@saua: Benar, tetapi mungkin seseorang akan memposting beberapa kode contoh tentang cara memisahkan nama pengguna dan sandi di Java. Saya bahkan mungkin melakukannya sendiri jika saya punya waktu.
William Brendel
1
Saya perhatikan bahwa banyak jawaban berpikir bahwa Anda mencoba menyembunyikan nama pengguna / kata sandi dari pengguna yang tidak sah sementara pengguna yang menjalankan aplikasi tidak apa-apa. Saya yakin Anda ingin menyembunyikan sandi dari SEMUA ORANG . Mohon klarifikasi hal ini dalam pertanyaan.
pek
1
Misalnya, kredensial digunakan untuk menyambung ke server yang tidak dapat masuk selain aplikasi.
pek

Jawaban:

124

Jangan pernah memasukkan kata sandi ke dalam kode Anda. Hal ini baru-baru ini diangkat dalam 25 Kesalahan Pemrograman Paling Berbahaya Teratas :

Melakukan hard-coding akun rahasia dan kata sandi ke dalam perangkat lunak Anda sangat nyaman - untuk insinyur yang terampil. Jika kata sandi sama di semua perangkat lunak Anda, maka setiap pelanggan menjadi rentan ketika kata sandi itu pasti diketahui. Dan karena ini memiliki kode keras, sangat sulit untuk memperbaikinya.

Anda harus menyimpan informasi konfigurasi, termasuk sandi, dalam file terpisah yang dibaca aplikasi saat dijalankan. Itu adalah satu-satunya cara nyata untuk mencegah kata sandi bocor akibat dekompilasi (jangan pernah mengkompilasinya ke dalam biner untuk memulai).

Untuk informasi selengkapnya tentang kesalahan umum ini, Anda dapat membaca artikel CWE-259 . Artikel tersebut berisi definisi yang lebih menyeluruh, contoh, dan banyak informasi lain tentang masalah tersebut.

Di Java, salah satu cara termudah untuk melakukannya adalah dengan menggunakan kelas Preferensi. Ini dirancang untuk menyimpan semua jenis pengaturan program, beberapa di antaranya dapat menyertakan nama pengguna dan kata sandi.

import java.util.prefs.Preferences;

public class DemoApplication {
  Preferences preferences = 
      Preferences.userNodeForPackage(DemoApplication.class);

  public void setCredentials(String username, String password) {
    preferences.put("db_username", username);
    preferences.put("db_password", password);
  }

  public String getUsername() {
    return preferences.get("db_username", null);
  }

  public String getPassword() {
    return preferences.get("db_password", null);
  }

  // your code here
}

Pada kode di atas, Anda dapat memanggil setCredentialsmetode tersebut setelah menampilkan dialog askign untuk nama pengguna dan kata sandi. Saat Anda perlu menyambungkan ke database, Anda cukup menggunakan metode getUsernamedan getPassworduntuk mengambil nilai yang disimpan. Kredensial login tidak akan di-hardcode ke dalam biner Anda, jadi dekompilasi tidak akan menimbulkan risiko keamanan.

Catatan Penting: File preferensi hanyalah file XML teks biasa. Pastikan Anda mengambil langkah-langkah yang tepat untuk mencegah pengguna yang tidak sah melihat file mentah (izin UNIX, izin Windows, dan sebagainya). Di Linux, setidaknya, ini bukan masalah, karena pemanggilan Preferences.userNodeForPackageakan membuat file XML di direktori home pengguna saat ini, yang toh tidak bisa dibaca oleh pengguna lain. Di Windows, situasinya mungkin berbeda.

Lebih Banyak Catatan Penting: Ada banyak diskusi di komentar jawaban ini dan lainnya tentang apa arsitektur yang benar untuk situasi ini. Pertanyaan asli tidak benar-benar menyebutkan konteks di mana aplikasi tersebut digunakan, jadi saya akan berbicara tentang dua situasi yang dapat saya pikirkan. Yang pertama adalah kasus di mana orang yang menggunakan program sudah mengetahui (dan diberi wewenang untuk mengetahui) kredensial database. Yang kedua adalah kasus di mana Anda, pengembang, mencoba merahasiakan kredensial database dari orang yang menggunakan program.

Kasus Pertama: Pengguna diberi wewenang untuk mengetahui kredensial login database

Dalam hal ini, solusi yang saya sebutkan di atas akan berfungsi. Kelas Java Preferenceakan menyimpan nama pengguna dan kata sandi dalam teks biasa, tetapi file preferensi hanya akan dapat dibaca oleh pengguna yang berwenang. Pengguna cukup membuka file XML preferensi dan membaca kredensial login, tetapi itu bukan risiko keamanan karena pengguna tahu kredensial tersebut sejak awal.

Kasus Kedua: Mencoba menyembunyikan kredensial login dari pengguna

Ini adalah kasus yang lebih rumit: pengguna seharusnya tidak mengetahui kredensial login tetapi masih membutuhkan akses ke database. Dalam hal ini, pengguna yang menjalankan aplikasi memiliki akses langsung ke database, yang berarti program perlu mengetahui kredensial login sebelumnya. Solusi yang saya sebutkan di atas tidak sesuai untuk kasus ini. Anda dapat menyimpan kredensial login database dalam file preferensi, tetapi pengguna tersebut akan dapat membaca file itu, karena mereka akan menjadi pemiliknya. Faktanya, tidak ada cara yang baik untuk menggunakan kasing ini dengan cara yang aman.

Kasus yang Benar: Menggunakan arsitektur multi-tingkat

Cara yang benar untuk melakukannya adalah dengan memiliki lapisan tengah, di antara server database dan aplikasi klien Anda, yang mengautentikasi pengguna individu dan memungkinkan serangkaian operasi terbatas untuk dilakukan. Setiap pengguna akan memiliki kredensial login mereka sendiri, tetapi tidak untuk server database. Kredensial akan memungkinkan akses ke lapisan tengah (tingkat logika bisnis) dan akan berbeda untuk setiap pengguna.

Setiap pengguna akan memiliki nama pengguna dan kata sandi mereka sendiri, yang dapat disimpan secara lokal di file preferensi tanpa risiko keamanan. Ini disebut arsitektur tiga tingkat (tingkatannya adalah server database Anda, server logika bisnis, dan aplikasi klien). Ini lebih kompleks, tetapi ini adalah cara paling aman untuk melakukan hal semacam ini.

Urutan operasi dasar adalah:

  1. Klien mengautentikasi dengan tingkat logika bisnis menggunakan nama pengguna / kata sandi pribadi pengguna. Nama pengguna dan kata sandi diketahui oleh pengguna dan tidak terkait dengan kredensial login database dengan cara apa pun.
  2. Jika otentikasi berhasil, klien membuat permintaan ke tingkat logika bisnis meminta beberapa informasi dari database. Misalnya, inventaris produk. Perhatikan bahwa permintaan klien bukanlah kueri SQL; itu adalah panggilan prosedur jarak jauh seperti getInventoryList.
  3. Tingkat logika bisnis terhubung ke database dan mengambil informasi yang diminta. Tingkat logika bisnis bertanggung jawab untuk membentuk kueri SQL yang aman berdasarkan permintaan pengguna. Parameter apa pun pada kueri SQL harus dibersihkan untuk mencegah serangan injeksi SQL.
  4. Tingkat logika bisnis mengirimkan daftar inventaris kembali ke aplikasi klien.
  5. Klien menampilkan daftar inventaris kepada pengguna.

Perhatikan bahwa di seluruh proses, aplikasi klien tidak pernah terhubung langsung ke database . Tingkat logika bisnis menerima permintaan dari pengguna yang diautentikasi, memproses permintaan klien untuk daftar inventaris, dan hanya kemudian menjalankan kueri SQL.

William Brendel
sumber
4
Bagaimana tepatnya ini mencegah seseorang mendapatkan nama pengguna / kata sandi? Tidak bisakah kamu membacanya dari file itu?
Joe Phillips
Seperti yang saya katakan dalam jawaban saya, jika izin file Anda diatur dengan benar, hanya pengguna yang menjalankan program yang memiliki akses membaca ke file preferensi itu. Di lingkungan UNIX, ini dilakukan secara otomatis. Windows mungkin memerlukan langkah tambahan (saya benar-benar tidak yakin, karena saya tidak banyak menggunakan Windows).
William Brendel
Saya pikir idenya adalah bahwa pengguna yang menjalankan aplikasi bukanlah orang yang Anda coba untuk jaga. Jika demikian, maka Anda harus mengenkripsinya.
Michael Haren
Ya, Michael benar. Pada dasarnya idenya adalah Anda sudah mengetahui nama pengguna / kata sandi, jadi tidak perlu menyembunyikannya dari diri Anda sendiri. Ini akan disembunyikan dari pengguna lain, bagaimanapun, melalui izin file.
William Brendel
7
Jika Anda menerapkan (contoh) aplikasi pengeditan DB ke pengguna dan Anda tidak ingin mereka mengetahui nama pengguna database dan kata sandi, maka Anda salah merancang solusi, dan perangkat lunak klien harus berkomunikasi dengan server (melalui misalnya, layanan web) yang melakukan tugas DB.
JeeBee
15

Masukkan kata sandi ke dalam file yang akan dibaca aplikasi. JANGAN PERNAH menyematkan kata sandi dalam file sumber. Titik.

Ruby memiliki modul yang kurang dikenal bernama DBI :: DBRC untuk penggunaan semacam itu. Saya tidak ragu bahwa Java memiliki padanan. Bagaimanapun, tidak sulit untuk menulisnya.

Keltia
sumber
7
Meskipun itu membuatnya sedikit lebih mudah untuk mengubah kata sandi nanti, itu tidak menyelesaikan masalah keamanan dasar.
Brian Knoblauch
Ya, itu benar. Lihat juga jawaban dari William Brendel.
Keltia
1
Metode yang saya dan Keltia tunjukkan adalah cara yang diterima untuk menangani masalah ini. Memisahkan kredensial login Anda dari kode yang dikompilasi adalah salah satu praktik keamanan perangkat lunak paling dasar. Menempatkan kredensial login dalam file terpisah adalah cara yang efektif untuk mencapai ini.
William Brendel
Selain itu, fakta bahwa informasi konfigurasi Anda dalam file teks biasa harus dibatalkan oleh batasan sistem operasi. Misalnya, di UNIX, file teks biasa harus dimiliki oleh pengguna yang menjalankan program dan memiliki izin 0600, jadi hanya pemilik yang dapat membacanya.
William Brendel
4
Oke, jadi file hanya bisa dibaca oleh pengguna yang menjalankan program. Bagus. Itu tidak menyelesaikan apa pun. :-) Saya, pengguna yang kami coba rahasiakan sandi, dapat membacanya semudah aplikasi ...
Brian Knoblauch
3

Apakah Anda sedang menulis aplikasi web? Jika demikian, gunakan JNDI untuk mengkonfigurasinya secara eksternal ke aplikasi. Ringkasan tersedia di sini :

JNDI menyediakan cara yang seragam bagi aplikasi untuk menemukan dan mengakses layanan jarak jauh melalui jaringan. Layanan jarak jauh dapat berupa layanan perusahaan apa pun, termasuk layanan pesan atau layanan khusus aplikasi, tetapi, tentu saja, aplikasi JDBC tertarik terutama pada layanan database. Setelah objek DataSource dibuat dan didaftarkan dengan layanan penamaan JNDI, aplikasi dapat menggunakan JNDI API untuk mengakses objek DataSource tersebut, yang kemudian dapat digunakan untuk menyambungkan ke sumber data yang diwakilinya.

Tim Howland
sumber
tautan yang disediakan buruk
James Oravec
2

Apa pun yang Anda lakukan, informasi sensitif akan disimpan di beberapa file di suatu tempat. Tujuan Anda adalah membuatnya sesulit mungkin. Berapa banyak dari ini yang dapat Anda capai tergantung pada proyek Anda, kebutuhan dan ketebalan dompet perusahaan Anda.

Cara terbaik adalah dengan tidak menyimpan sandi apa pun di mana pun. Ini dicapai dengan menggunakan fungsi hash untuk menghasilkan dan menyimpan hash kata sandi:

hash("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
hash("hbllo") = 58756879c05c68dfac9866712fad6a93f8146f337a69afe7dd238f3364946366

Algoritma hash adalah fungsi satu arah. Mereka mengubah sejumlah data menjadi "sidik jari" dengan panjang tetap yang tidak dapat dibalik. Mereka juga memiliki properti bahwa jika input berubah bahkan sedikit, hash yang dihasilkan sangat berbeda (lihat contoh di atas). Ini bagus untuk melindungi kata sandi, karena kami ingin menyimpan kata sandi dalam bentuk yang melindungi mereka bahkan jika file kata sandi itu sendiri disusupi, tetapi pada saat yang sama, kami harus dapat memverifikasi bahwa kata sandi pengguna benar.

Catatan tidak terkait: Di masa lalu internet, ketika Anda mengklik tautan 'lupa kata sandi saya', situs web akan mengirimi Anda kata sandi teks biasa Anda melalui email. Mereka mungkin menyimpannya dalam database di suatu tempat. Ketika peretas mendapatkan akses ke database mereka, mereka akan mendapatkan akses ke semua kata sandi. Karena banyak pengguna akan menggunakan kata sandi yang sama di banyak situs web, ini adalah masalah keamanan yang sangat besar. Untungnya, sekarang ini bukan praktik yang umum.

Sekarang muncul pertanyaan: apa cara terbaik untuk menyimpan kata sandi? Saya akan menganggap solusi (otentikasi dan layanan manajemen pengguna stormpath) ini sangat ideal:

  1. Pengguna Anda memasukkan kredensial, dan ini divalidasi dengan hash kata sandi
  2. Hash sandi dibuat dan disimpan, bukan sandi
  3. Hash dilakukan beberapa kali
  4. Hash dibuat menggunakan garam yang dibuat secara acak
  5. Hash dienkripsi dengan kunci pribadi
  6. Kunci pribadi disimpan di tempat yang secara fisik berbeda dari hash
  7. Kunci pribadi dengan mode berbasis waktu diperbarui
  8. Hash terenkripsi dibagi menjadi beberapa bagian
  9. Potongan ini disimpan di lokasi yang terpisah secara fisik

Jelas Anda bukan google atau bank, jadi ini adalah solusi yang berlebihan untuk Anda. Tetapi kemudian muncul pertanyaan: Berapa banyak keamanan yang dibutuhkan proyek Anda, berapa banyak waktu dan uang yang Anda miliki?

Untuk banyak aplikasi, meskipun tidak disarankan, menyimpan sandi dengan kode keras dalam kode mungkin merupakan solusi yang cukup baik. Namun, dengan menambahkan beberapa langkah keamanan ekstra dengan mudah dari daftar di atas, Anda dapat membuat aplikasi Anda jauh lebih aman.

Misalnya, anggap saja langkah 1 bukanlah solusi yang dapat diterima untuk proyek Anda. Anda tidak ingin pengguna memasukkan kata sandi setiap saat, atau Anda bahkan tidak ingin / perlu pengguna mengetahui kata sandinya. Anda masih memiliki informasi sensitif di suatu tempat dan Anda ingin melindungi ini. Anda memiliki aplikasi sederhana, tidak ada server untuk menyimpan file Anda atau ini terlalu merepotkan proyek Anda. Aplikasi Anda berjalan di lingkungan yang tidak memungkinkan untuk menyimpan file dengan aman. Ini adalah salah satu kasus terburuk, tetapi masih dengan beberapa tindakan keamanan tambahan, Anda dapat memiliki solusi yang jauh lebih aman. Misalnya, Anda dapat menyimpan informasi sensitif dalam sebuah file, dan Anda dapat mengenkripsi file tersebut. Anda dapat memiliki kunci pribadi enkripsi yang di-hardcode dalam kode. Anda dapat mengaburkan kode tersebut, sehingga Anda mempersulit seseorang untuk memecahkannya.tautan ini . (Saya ingin memperingatkan Anda sekali lagi bahwa ini tidak 100% aman. Seorang peretas cerdas dengan pengetahuan dan alat yang tepat dapat meretas ini. Tetapi berdasarkan kebutuhan dan kebutuhan Anda, ini mungkin solusi yang cukup baik untuk Anda).

Caner
sumber
1

Pertanyaan ini menunjukkan cara menyimpan kata sandi dan data lain dalam file terenkripsi: Java 256-bit AES Password-Based Encryption

Aaron Digulla
sumber
1
Di suatu tempat di kode sumber masih perlu mendekripsi kata sandi terenkripsi untuk membuat koneksi, kata sandi yang dianggap ini masih ada.
Bear0x3f
0

MD5 adalah algoritma hash, bukan algoritma enkripsi, singkatnya u cant mendapatkan kembali wat u hash, u hanya dapat membandingkan. Ini idealnya digunakan saat menyimpan informasi otentikasi pengguna dan bukan nama pengguna dan kata sandi db. db username dan pwd harus dienkripsi dan disimpan dalam file konfigurasi, untuk melakukan paling sedikit.

renegadeMind
sumber
Saya pernah mendengar tentang orang-orang yang menghasilkan semua kemungkinan kombinasi string dan menyimpan hash MD5 yang sesuai. Jadi ketika mereka menemukan hash MD5 seseorang, mereka hanya menemukan hash yang mereka simpan, dan mereka mendapatkan string yang sesuai.
Nav