Bagaimana cara mengamankan kata sandi basis data dalam PHP?

404

Ketika aplikasi PHP membuat koneksi database itu tentu saja pada umumnya perlu melewati login dan kata sandi. Jika saya menggunakan satu, izin masuk minimum untuk aplikasi saya, maka PHP perlu mengetahui login dan kata sandi itu di suatu tempat. Apa cara terbaik untuk mengamankan kata sandi itu? Sepertinya hanya menulisnya dalam kode PHP bukan ide yang baik.

pengguna18359
sumber
1
Agar benar-benar aman, Anda harus mengatur koneksi ssl, jika tidak siapa pun di jaringan Anda masih dapat mengendus kata sandi yang Anda ketikkan.
Charles Ma
1
Apakah maksud Anda kata sandi pengguna atau kata sandi basis data yang digunakan dalam string koneksi?
Ozgur Ozcitak
4
Kata sandi basis data yang digunakan dalam string koneksi. Terima kasih!
user18359

Jawaban:

238

Beberapa orang salah membaca ini sebagai pertanyaan tentang cara menyimpan kata sandi dalam database. Itu salah. Ini tentang bagaimana cara menyimpan kata sandi yang memungkinkan Anda sampai ke basis data.

Solusi yang biasa adalah memindahkan kata sandi dari kode sumber ke file konfigurasi. Kemudian tinggalkan administrasi dan mengamankan file konfigurasi itu ke administrator sistem Anda. Dengan begitu pengembang tidak perlu tahu apa-apa tentang kata sandi produksi, dan tidak ada catatan kata sandi di kontrol-sumber Anda.

pengguna11318
sumber
8
Terima kasih. Jika saya mengerti ini dengan benar, file php kemudian akan memiliki sebuah menyertakan ke file konfigurasi, memungkinkannya untuk menggunakan kata sandi. misal saya membuat file bernama 'app1_db_cfg.php' yang menyimpan nama login, pword, & db. Lalu halaman application.php saya termasuk 'app1_db_cfg.php' dan saya dalam bisnis!
user18359
28
Saya setuju bahwa konfigurasi perlu dilindungi dengan benar. Namun mengetahui bagaimana melakukan itu adalah urusan administrator sistem, bukan pengembang. Saya tidak setuju pada nilai enkripsi kuat dalam kasus ini. Jika Anda tidak dapat melindungi file konfigurasi Anda, apa yang membuat Anda berpikir Anda dapat melindungi kunci Anda?
user11318
10
Saya lebih suka menggunakan akun basis data yang hanya diperbolehkan untuk mengakses basis data dari server web. Dan kemudian saya tidak repot mengenkripsi konfigurasi, saya hanya menyimpannya di luar root web.
gnud
11
Saya menggunakan variabel lingkungan apache untuk mengatur path sehingga bahkan path ke file tidak diketahui dalam kode sumber. Ini juga memungkinkan memiliki kata sandi yang berbeda untuk pengembangan dan produksi berdasarkan apa pengaturan Apache pada serverm
geedew
15
Harap diingat bahwa bahkan file yang disimpan di luar direktori yang dapat diakses web harus dibaca oleh skrip yang menggunakannya. Jika seseorang memasukkan file itu, kemudian membuang data dari file tersebut, mereka akan melihat kata sandi.
Rick Mac Gillis
104

Jika Anda hosting di server orang lain dan tidak memiliki akses di luar webroot Anda, Anda selalu dapat memasukkan kata sandi dan / atau koneksi database dalam file dan kemudian mengunci file menggunakan .htaccess:

<files mypasswdfile>
order allow,deny
deny from all
</files>
Kellen
sumber
3
Terima kasih, itulah tepatnya yang saya cari.
David Gladfelter
28
Tentu saja, tetapi jika seseorang memiliki akses shell, seluruh akun Anda telah dikompromikan.
kellen
4
Ini adalah praktik buruk karena Anda mungkin secara tidak sengaja menyerahkan kredensial Anda ke repositori.
Porlune,
2
@Ankit: Jika mungkin bagi yang tidak ramah untuk mengunggah file ke server dan menjalankannya, maka server tidak dikonfigurasikan dengan benar.
kellen
6
@Porlune: Pengembang harus membuat sistem kontrol versinya mengabaikan file kata sandi, yaitu dengan menggunakan .gitignore. Tapi ya, harus diperhatikan dengan file yang berisi data sensitif.
kellen
45

Cara paling aman adalah tidak memiliki informasi yang ditentukan dalam kode PHP Anda sama sekali.

Jika Anda menggunakan Apache, itu berarti mengatur detail koneksi di file file httpd.conf atau host virtual Anda. Jika Anda melakukannya, Anda dapat memanggil mysql_connect () tanpa parameter, yang berarti PHP tidak akan pernah menampilkan informasi Anda.

Ini adalah bagaimana Anda menentukan nilai-nilai ini di file-file itu:

php_value mysql.default.user      myusername
php_value mysql.default.password  mypassword
php_value mysql.default.host      server

Kemudian Anda membuka koneksi mysql Anda seperti ini:

<?php
$db = mysqli_connect();

Atau seperti ini:

<?php
$db = mysqli_connect(ini_get("mysql.default.user"),
                     ini_get("mysql.default.password"),
                     ini_get("mysql.default.host"));
Lars Nyström
sumber
1
Silakan periksa nilai yang tepat dari ini_get ('nilai default') php.net/manual/en/class.mysqli.php
Val
4
ya, tetapi setiap pengguna (atau peretas yang menggunakan skrip php yang ditulis dengan buruk) dapat membaca kata sandi melalui ini_get().
Marki555
1
@ Marki555 but any user (or a hacker abusing badly written php script) can read the password via ini_get()Bagaimana Anda menangani ini?
tonix
2
Marki555 mengatakan bahwa seorang penyerang yang dapat menjalankan kode PHP juga dapat memanggil fungsi-fungsi PHP, yang jelas benar dan tidak mungkin dilakukan sesuatu. Saya juga ingin menambahkan bahwa saya tidak lagi mengikuti saran yang saya berikan dalam jawaban ini sendiri, tetapi menggunakan variabel lingkungan. Konsepnya serupa: Jangan menyimpan kredensial Anda dalam kode, tetapi masukkan mereka entah bagaimana. Tidak masalah jika Anda menggunakan ini_get()atau getenv().
Lars Nyström
2
@DeepBlue Jika Anda bisa menyuntikkan ini_get () Anda juga bisa menyuntikkan file_get_contents (anypath). Selama php memiliki cara untuk mendapatkan kata sandi, demikian juga kode jahat apa pun.
varesa
40

Simpan di file di luar root web.

da5id
sumber
29
Dan juga, seperti yang disebutkan di tempat lain, di luar kendali sumber.
Frank Farmer
6
kita akan bisa memasukkannya? misalnya dalam PHP, bisakah kita melakukannya include('../otherDirectory/configfile.conf')?
mtk
1
Anda semua menyarankan untuk menyimpan kredensial di luar wwwroot. Ok, saya mengerti latar belakang keamanan. Tapi bagaimana seharusnya disimpan dalam kontrol versi (konfigurasi sampel)? Biasanya wwwroot adalah root dari git repo, jadi jika ada sesuatu di luar - itu akan berada di luar VC. Bayangkan pengembang baru mencoba membuat contoh lokal untuk pengembangan - bagaimana dia bisa tahu sihir seperti "ambil file ini, salin di luar, dan isi"?
The Godfather
@TheGodfather Idenya adalah bahwa pengembang baru harus memiliki kredensial mereka sendiri untuk lingkungan pengembangan mereka sendiri. Meskipun merupakan praktik yang baik untuk memiliki readme dengan instruksi atau komentar dalam kode yang menunjukkan bagaimana Anda harus mengkonfigurasinya (tetapi bukan data aktual).
PhoneixS
@TheGodfather, file readme?
Pacerier
35

Untuk sistem yang sangat aman kami mengenkripsi kata sandi basis data dalam file konfigurasi (yang dengan sendirinya diamankan oleh administrator sistem). Pada startup aplikasi / server aplikasi kemudian meminta administrator sistem untuk kunci dekripsi. Kata sandi basis data kemudian dibaca dari file konfigurasi, didekripsi, dan disimpan dalam memori untuk digunakan di masa mendatang. Masih tidak 100% aman karena disimpan dalam memori yang didekripsi, tetapi Anda harus menyebutnya 'cukup aman' di beberapa titik!

pdavis
sumber
85
bagaimana jika admin meninggal?
Radu Murzea
36
@ RaduMurzea itu konyol. Kapan Anda pernah mendengar tentang Sys Admin yang sekarat? Mereka seperti McDonalds, mereka hanya muncul / menghilang entah dari mana!
ILikeTacos
13
@ Radu Murzea Hanya memiliki 2 atau lebih admin, maka Anda memiliki paritas seperti array serangan. Peluang lebih dari satu drive gagal pada suatu waktu jauh lebih rendah.
element11
5
bagaimana dengan kapan server restart? Bagaimana dengan waktu yang dibutuhkan untuk membangunkan admin untuk membuat mereka mengetikkan kata sandi..etc.etc. lol
John Hunt
1
Tidak yakin apa yang Anda maksud dengan 'tersimpan dalam memori'. Aplikasi web PHP umumnya tidak menyimpan apa pun dalam memori lebih lama dari waktu yang dibutuhkan untuk menanggapi permintaan individu untuk melihat halaman.
bdsl
15

Solusi ini bersifat umum, karena berguna untuk aplikasi sumber terbuka dan tertutup.

  1. Buat pengguna OS untuk aplikasi Anda. Lihat http://en.wikipedia.org/wiki/Principle_of_least_privilege
  2. Buat variabel lingkungan OS (non-sesi) untuk pengguna itu, dengan kata sandi
  3. Jalankan aplikasi sebagai pengguna itu

Keuntungan:

  1. Anda tidak akan memeriksa kata sandi Anda menjadi kontrol sumber secara tidak sengaja, karena Anda tidak bisa
  2. Anda tidak akan secara tidak sengaja mengacaukan izin file. Ya, Anda mungkin, tetapi itu tidak akan memengaruhi ini.
  3. Hanya bisa dibaca oleh root atau pengguna itu. Root dapat membaca semua file dan kunci enkripsi Anda.
  4. Jika Anda menggunakan enkripsi, bagaimana Anda menyimpan kunci dengan aman?
  5. Bekerja x-platform
  6. Pastikan untuk tidak mengirimkan envvar ke proses anak yang tidak dipercaya

Metode ini disarankan oleh Heroku, yang sangat sukses.

Neil McGuigan
sumber
11

jika memungkinkan untuk membuat koneksi database di file yang sama di mana kredensial disimpan. Sebariskan kredensial di pernyataan hubungkan.

mysql_connect("localhost", "me", "mypass");

Jika tidak, sebaiknya hapus kredensial setelah pernyataan hubungkan, karena kredensial yang tidak ada dalam memori, tidak dapat dibaca dari memori ;)

include("/outside-webroot/db_settings.php");  
mysql_connect("localhost", $db_user, $db_pass);  
unset ($db_user, $db_pass);  
Bob Fanger
sumber
9
Jika seseorang memiliki akses ke memori, Anda tetap kacau. Ini adalah keamanan palsu yang tidak berguna. Di luar webroot (atau paling tidak dilindungi oleh .htaccess jika Anda tidak memiliki akses di atas webroot Anda) adalah satu-satunya pilihan yang aman.
uliwitness
2
@uliwitness - Itu seperti mengatakan bahwa hanya karena seseorang dapat memotong kunci pusat operasi jaringan Anda dengan obor asetilena berarti pintu itu juga keamanan palsu. Menjaga informasi sensitif terikat pada cakupan sekecil mungkin selalu masuk akal.
Luke A. Leber
1
Bagaimana dengan echo $ db_user atau mencetak $ db_pass? Bahkan pengembang di tim yang sama seharusnya tidak dapat mengetahui kredensial produksi. Kode tidak boleh memuat apa pun yang dapat dicetak tentang info masuk.
Mohammed Joraid
8

Pilihan Anda agak terbatas karena seperti yang Anda katakan Anda perlu kata sandi untuk mengakses database. Salah satu pendekatan umum adalah menyimpan nama pengguna dan kata sandi dalam file konfigurasi terpisah daripada skrip utama. Kemudian pastikan untuk menyimpannya di luar pohon web utama. Itu jika ada masalah konfigurasi web yang membuat file php Anda hanya ditampilkan sebagai teks daripada dieksekusi Anda belum membuka kata sandi.

Selain itu Anda berada di jalur yang benar dengan akses minimal untuk akun yang sedang digunakan. Tambahkan itu

  • Jangan gunakan kombinasi nama pengguna / kata sandi untuk hal lain
  • Konfigurasikan server basis data untuk hanya menerima koneksi dari host web untuk pengguna tersebut (localhost bahkan lebih baik jika DB berada di mesin yang sama) Dengan cara itu bahkan jika kredensial diekspos mereka tidak digunakan untuk siapa pun kecuali mereka memiliki akses lain ke mesin.
  • Mengaburkan kata sandi (bahkan ROT13 akan melakukannya) itu tidak akan membuat banyak pertahanan jika beberapa tidak mendapatkan akses ke file, tetapi setidaknya itu akan mencegah tampilan biasa itu.

Peter

Vagnerr
sumber
8

Jika Anda menggunakan PostgreSQL, maka ~/.pgpasskata sandi akan dicari secara otomatis. Lihat manual untuk informasi lebih lanjut.

Jim
sumber
8

Sebelumnya kami menyimpan pengguna DB / pass dalam file konfigurasi, tetapi sejak itu tekan mode paranoid - mengadopsi kebijakan Defense in Depth .

Jika aplikasi Anda dikompromikan, pengguna akan memiliki akses baca ke file konfigurasi Anda sehingga ada kemungkinan cracker membaca informasi ini. File konfigurasi juga dapat terperangkap dalam kontrol versi, atau disalin di sekitar server.

Kami telah beralih ke menyimpan variabel lingkungan pengguna / pass yang ditetapkan di Apache VirtualHost. Konfigurasi ini hanya dapat dibaca oleh root - semoga pengguna Apache Anda tidak berjalan sebagai root.

Yang salah dengan ini adalah bahwa sekarang kata sandi dalam variabel PHP Global.

Untuk mengurangi risiko ini, kami memiliki tindakan pencegahan berikut:

  • Kata sandi dienkripsi. Kami memperluas kelas PDO untuk memasukkan logika untuk mendekripsi kata sandi. Jika seseorang membaca kode tempat kami membuat koneksi, tidak akan jelas bahwa koneksi dibuat dengan kata sandi terenkripsi dan bukan kata sandi itu sendiri.
  • Kata sandi terenkripsi dipindahkan dari variabel global ke variabel pribadi . Aplikasi melakukan ini segera untuk mengurangi jendela bahwa nilai tersedia di ruang global.
  • phpinfo()dinonaktifkan. PHPInfo adalah target yang mudah untuk mendapatkan gambaran umum tentang segala sesuatu, termasuk variabel lingkungan.
Courtney Miles
sumber
6

Masukkan kata sandi basis data ke dalam file, buat hanya-baca untuk pengguna yang melayani file.

Kecuali Anda memiliki beberapa cara yang hanya memungkinkan proses server php untuk mengakses database, ini cukup banyak yang dapat Anda lakukan.

Chris
sumber
5

Jika Anda berbicara tentang kata sandi basis data, dan bukan kata sandi yang berasal dari peramban, praktik standar tampaknya adalah memasukkan kata sandi basis data dalam file konfigurasi PHP di server.

Anda hanya perlu memastikan bahwa file php yang berisi kata sandi memiliki izin yang sesuai. Yaitu itu harus dapat dibaca hanya oleh server web dan oleh akun pengguna Anda.

Jason Wadsworth
sumber
1
Sayangnya file konfigurasi PHP dapat dibaca oleh phpinfo () dan jika seseorang meninggalkan beberapa script tes di belakang penyerang yang beruntung akan dapat membaca kata sandi. Mungkin lebih baik meninggalkan kata sandi koneksi dalam file di luar root server web. Maka satu-satunya cara untuk mengaksesnya adalah dengan menggunakan shell atau dengan mengeksekusi kode arbitrer, tetapi dalam skenario itu semua keamanan tetap hilang.
MarioVilas
5

Hanya memasukkannya ke file konfigurasi di suatu tempat adalah cara yang biasanya dilakukan. Pastikan Anda:

  1. larang akses basis data dari server mana pun di luar jaringan Anda,
  2. berhati-hatilah agar tidak secara tidak sengaja menunjukkan kata sandi kepada pengguna (dalam pesan kesalahan, atau melalui file PHP yang secara tidak sengaja disajikan sebagai HTML, dan sebagainya.)
Marijn
sumber
5

Kami telah menyelesaikannya dengan cara ini:

  1. Gunakan memcache di server, dengan koneksi terbuka dari server kata sandi lain.
  2. Simpan untuk memcache kata sandi (atau bahkan semua file password.php terenkripsi) ditambah kunci dekripsi.
  3. Situs web, memanggil kunci memcache yang memegang kata sandi file kata sandi dan mendekripsi dalam memori semua kata sandi.
  4. Server kata sandi mengirim file kata sandi terenkripsi baru setiap 5 menit.
  5. Jika Anda menggunakan password.php terenkripsi pada proyek Anda, Anda melakukan audit, yang memeriksa apakah file ini disentuh secara eksternal - atau dilihat. Ketika ini terjadi, Anda secara otomatis dapat membersihkan memori, serta menutup server untuk akses.
Asi Azulay
sumber
4

Trik tambahan adalah dengan menggunakan file konfigurasi PHP terpisah yang terlihat seperti itu:

<?php exit() ?>

[...]

Plain text data including password

Ini tidak mencegah Anda dari menetapkan aturan akses dengan benar. Tetapi dalam kasus situs web Anda diretas, "harus" atau "sertakan" hanya akan keluar dari skrip di baris pertama sehingga lebih sulit untuk mendapatkan data.

Meskipun demikian, jangan pernah membiarkan file konfigurasi dalam direktori yang dapat diakses melalui web. Anda harus memiliki folder "Web" yang berisi kode, css, gambar, dan js. Itu saja. Ada lagi yang masuk dalam folder offline.

e-satis
sumber
tetapi kemudian bagaimana skrip php membaca kredensial yang disimpan dalam file?
Christopher Mahan
3
Anda menggunakan fopen (), seperti untuk file teks biasa.
e-satis
2
@ e-satis ok itu akan mencegah hacker untuk melakukan require/ includetetapi bagaimana mencegahnya fopen?
dmnc
"ini tidak mencegah Anda dari menetapkan aturan akses dengan benar"
e-satis
@ e-satis, ini cukup pintar. bertanya-tanya mengapa tidak ada yang memikirkannya. Namun , masih rentan terhadap masalah penyalinan editor. feross.org/cmsploit
Pacerier
4

Cara terbaik adalah tidak menyimpan kata sandi sama sekali!
Misalnya, jika Anda menggunakan sistem Windows, dan terhubung ke SQL Server, Anda dapat menggunakan Otentikasi Terintegrasi untuk terhubung ke database tanpa kata sandi, menggunakan identitas proses saat ini.

Jika Anda perlu terhubung dengan kata sandi, pertama-tama enkripsinya , menggunakan enkripsi yang kuat (mis. Menggunakan AES-256, dan kemudian lindungi kunci enkripsi, atau gunakan enkripsi asimetris dan mintalah OS melindungi sertifikat), dan kemudian simpan dalam file konfigurasi (di luar direktori web) dengan ACL yang kuat .

Keranjingan
sumber
3
Tidak ada gunanya mengenkripsi kata sandi lagi . Seseorang yang bisa mendapatkan kata sandi yang tidak dienkripsi juga bisa mendapatkan kata sandi apa pun yang diperlukan untuk mendekripsi kata sandi. Namun, menggunakan ACL & .htaccess adalah ide yang bagus.
uliwitness
2
@uliwitness Saya pikir Anda mungkin salah paham - apa maksud Anda dengan "mengenkripsi lagi "? Hanya satu enkripsi. Dan Anda tidak ingin menggunakan kata sandi (dimaksudkan untuk penggunaan manusia) untuk mengenkripsi, manajemen kunci yang agak kuat, misalnya dilindungi oleh OS, sedemikian rupa sehingga hanya mengakses sistem file tidak akan memberikan akses ke kunci.
AviD
3
Enkripsi bukan sihir - alih-alih melindungi kunci AES dengan ACL Anda bisa menyimpan kata sandi di sana. Tidak ada perbedaan antara mengakses kunci AES atau kata sandi yang didekripsi, enkripsi dalam konteks ini hanya minyak ular.
MarioVilas
@MarioVilas apa? Jika kata sandi dienkripsi, dengan kunci enkripsi dilindungi oleh OS, bagaimana tidak ada perbedaan? Enkripsi bukanlah sihir - itu hanya memadatkan semua kerahasiaan menjadi kunci enkripsi yang lebih kecil. Hampir tidak ular, dalam konteks ini hanya memindahkan semua kerahasiaan ke dalam OS.
AviD
6
@Vivi kok OS bisa melindungi kunci tetapi tidak data itu sendiri? Jawaban: ini dapat melindungi keduanya, jadi enkripsi tidak terlalu membantu. Akan berbeda jika hanya data yang disimpan dan kunci enkripsi berasal, misalnya, dari kata sandi yang harus diketik oleh pengguna.
MarioVilas