Terkadang kita perlu menyebarkan nilai variabel sensitif dan rahasia dalam logika aplikasi kita. Ambil kode login ini sebagai contoh
1<?php
2
3class AccessBroker
4{
5 public function login(string $username, string $password): void
6 {
7 // Pretend that we're attempting to log the user in, but something throws an exception.
8 throw new \Exception('Oops, something went wrong!');
9 }
10}
11
12(new AccessBroker)->login($_POST['username'], $_POST['password']);
Saya sengaja menyimpan framework-agnostik dan dasar ini hanya untuk menunjukkan masalahnya. Saat kode di atas dijalankan, kita dapat dengan jelas melihat kata sandi pengguna di jejak tumpukan pengecualian
1Fatal error: Uncaught Exception: Oops, something went wrong! in /in/HhjIr:8
2Stack trace:
3#0 /in/HhjIr(13): AccessBroker->login('chris', 'secret password')
4#1 {main}
5 thrown in /in/HhjIr on line 8
_Ini mungkin bukan masalah besar bagi Anda, lagipula, Anda harus menonaktifkan rendering jejak tumpukan dalam produksi. Tidak seorang pun akan memiliki kesempatan untuk melihat nilainya, bukan? . Jika pengecualian ini dilaporkan ke layanan eksternal untuk pemantauan kesalahan, seperti Sentry atau Bugsnag, Anda juga akan membocorkan kata sandi pengguna ke layanan orang lain. Paling tidak, Anda mungkin membocorkan nilai sensitif ke dalam file log Anda
Jadi apa yang bisa kita lakukan untuk melindungi rahasia itu? . Kita dapat melakukannya dengan berbagai metode berbeda
zend.exception_ignore_args
PHP 7. 4 memperkenalkan nilai konfigurasi ini baru yang disebut zend.exception_ignore_args. Ini akan berhenti merender pratinjau argumen metode dalam pelacakan tumpukan. Mengaktifkannya, pelacakan tumpukan kami tidak lagi mengungkapkan kata sandi pengguna
1Fatal error: Uncaught Exception: Oops, something went wrong! in /in/TYMID:10
2Stack trace:
3#0 /in/TYMID(14): AccessBroker->login()
4#1 {main}
5 thrown in /in/TYMID on line 10
Namun, ini datang dengan kerugian yang signifikan bahwa kami sekarang tidak akan mendapatkan pratinjau argumen apa pun di seluruh pelacakan tumpukan, dengan pengecualian apa pun yang dilemparkan oleh aplikasi kami. Karena sebagian besar argumen yang akan kami sampaikan dalam aplikasi kami tidak sensitif, menurut saya ini adalah pemecah kesepakatan
Sunting argumen individual secara manual
Kita dapat menulis penangan pengecualian yang dapat mengambil jejak tumpukan pengecualian melalui
1Fatal error: Uncaught Exception: Oops, something went wrong! in /in/HhjIr:8
2Stack trace:
3#0 /in/HhjIr(13): AccessBroker->login('chris', 'secret password')
4#1 {main}
5 thrown in /in/HhjIr on line 8
0, mengulangi bingkai, dan menyunting argumen apa pun yang ingin kita lindungi. Ada banyak jawaban Stack Overflow yang menunjukkan cara melakukannya. Masalah dengan metode ini adalah reaktif dan bukan proaktif. Saat Anda mulai meneruskan argumen rahasia baru lainnya di aplikasi Anda, Anda harus ingat untuk kembali ke penangan pengecualian dan memperbaruinya untuk memperhitungkan argumen baru. Dalam pengalaman saya, ini jarang terjadi 🙂Maaf menyela
Jika Anda menikmati membaca posting ini, silakan pertimbangkan untuk mengikuti saya di Twitter
Ikuti @cmwhite92
Gunakan array untuk menyimpan nilai rahasia
PHP tidak merender nilai array dalam pelacakan tumpukan secara default. Dengan menggunakan metode ini, kode masuk kami dari sebelumnya dapat terlihat seperti ini
1<?php
2
3class AccessBroker
4{
5 public function login(array $credentials)
6 {
7 // We can use $credentials['username'] and $credentials['password'].
8
9 // Pretend that we're attempting to log the user in, but something throws an exception.
10 throw new \Exception('Oops, something went wrong!');
11 }
12}
13
14(new AccessBroker)->login(['username' => 'chris', 'password' => 'secret password']);
_dan jejak tumpukan yang diberikan akan menjadi
1Fatal error: Uncaught Exception: Oops, something went wrong! in /in/37rTZ:8
2Stack trace:
3#0 /in/37rTZ(13): AccessBroker->login(Array)
4#1 {main}
5 thrown in /in/37rTZ on line 8
Ini adalah metode yang diambil oleh kerangka Laravel - dan ini bagus. Itu melakukan pekerjaan menyembunyikan argumen sensitif sambil menyimpan sisanya, dan tidak mengharuskan kita untuk menulis kode penanganan pengecualian kita sendiri untuk melakukannya
Gunakan objek untuk membungkus nilai sensitif
Sebagus metode di atas adalah memiliki satu kelemahan. Anda tidak lagi mendapatkan pelengkapan otomatis atau analisis statis untuk larik
1Fatal error: Uncaught Exception: Oops, something went wrong! in /in/HhjIr:8
2Stack trace:
3#0 /in/HhjIr(13): AccessBroker->login('chris', 'secret password')
4#1 {main}
5 thrown in /in/HhjIr on line 8
1 di dalam metode1Fatal error: Uncaught Exception: Oops, something went wrong! in /in/HhjIr:8
2Stack trace:
3#0 /in/HhjIr(13): AccessBroker->login('chris', 'secret password')
4#1 {main}
5 thrown in /in/HhjIr on line 8
2 karena Anda mengirimkan larik PHP umum. Kita bisa mengatasi masalah itu dengan mengganti array dengan objek1Fatal error: Uncaught Exception: Oops, something went wrong! in /in/HhjIr:8
2Stack trace:
3#0 /in/HhjIr(13): AccessBroker->login('chris', 'secret password')
4#1 {main}
5 thrown in /in/HhjIr on line 8
3 yang kita buat sendiri. Kode login kita dari sebelumnya adalah sekarang1<?php
2
3class ObfuscatedValue
4{
5 private $value;
6
7 public function __construct($value)
8 {
9 $this->value = $value;
10 }
11
12 public function value()
13 {
14 return $this->value;
15 }
16}
17
18class AccessBroker
19{
20 public function login(string $username, ObfuscatedValue $password)
21 {
22 // We can use $password->value() to get the real password value.
23
24 // Pretend that we're attempting to log the user in, but something throws an exception.
25 throw new \Exception('Oops, something went wrong!');
26 }
27}
28
29(new AccessBroker)->login('chris', new ObfuscatedValue('secret password'));
_dan sekali lagi, jejak tumpukan kami menyembunyikan kata sandi
1Fatal error: Uncaught Exception: Oops, something went wrong! in /in/Dnf3b:25
2Stack trace:
3#0 /in/Dnf3b(29): AccessBroker->login('chris', Object(ObfuscatedValue))
4#1 {main}
5 thrown in /in/Dnf3b on line 25
Gunakan perpustakaan
@julesjanssen menunjukkan di Twitter bahwa perpustakaan ada untuk melakukan hal ini yang sudah disebut string-tersembunyi. Ini terlihat sangat lengkap dan bahkan menggunakan metode ajaib yang saya tidak tahu disebut
1Fatal error: Uncaught Exception: Oops, something went wrong! in /in/HhjIr:8
2Stack trace:
3#0 /in/HhjIr(13): AccessBroker->login('chris', 'secret password')
4#1 {main}
5 thrown in /in/HhjIr on line 8
4. Anda dapat menggunakannya dengan cara yang sama seperti yang saya tunjukkan di atas, dan karena perpustakaan mengimplementasikan metode ajaib1Fatal error: Uncaught Exception: Oops, something went wrong! in /in/HhjIr:8
2Stack trace:
3#0 /in/HhjIr(13): AccessBroker->login('chris', 'secret password')
4#1 {main}
5 thrown in /in/HhjIr on line 8
5 Anda tidak perlu memperlakukan1Fatal error: Uncaught Exception: Oops, something went wrong! in /in/HhjIr:8
2Stack trace:
3#0 /in/HhjIr(13): AccessBroker->login('chris', 'secret password')
4#1 {main}
5 thrown in /in/HhjIr on line 8
6 seperti objek sama sekali