Doctor in the cloud: cara kami membuat layanan telemedicine untuk melawan virus corona di Luksemburg

Kami mulai mengembangkan platform ... secara tidak sengaja. Semuanya dimulai dengan pandemi, yang karenanya pemerintah Luksemburg memerintahkan pembuatan layanan konsultasi online dengan dokter. Untuk mendapatkan manfaat maksimal dari platform ini, mereka memutuskan untuk menambahkan semua yang diperlukan untuk pekerjaan penuh dokter dengan pasien. Pertukaran semua jenis dokumen medis dan bahkan penerbitan resep obat tidak terkecuali - vendor lama segera memasukkan semuanya ke dalam layanan. Dan kemudian, agar semua kebaikan aman, mereka beralih kepada kami dengan produk siap pakai - yang kami butuhkan hanyalah menerapkan platform di titik keberadaan cloud yang aman.



Satu setengah bulan kemudian, layanan berhasil bekerja di pusat data EDH Tingkat IV Luksemburg, tetapi bahkan pada pertemuan pertama, kami mengenalinya sebagai tautan yang lemah di seluruh proyek: tidak seperti titik kehadiran, platform tidak dapat membanggakan keamanan dan memiliki selusin kekurangan lainnya. Keputusannya jelas - layanan harus dilakukan dari awal. Tetap meyakinkan pemerintah Luksemburg.









Dokter ini rusak, bawa yang baru: mengapa kami memutuskan untuk membuat platform baru



Untuk menyarankan untuk meletakkan peluru di platform lama, kami hanya perlu melihatnya sekilas. Alih-alih memperbaiki semua kemungkinan masalah keamanan dan memperbarui desain, layanan ini lebih mudah dibuat dari awal, dan kami memiliki tiga alasan bagus untuk itu.



1. Sistem dikembangkan tanpa kerangka kerja



Karena itu, ada sejumlah masalah yang tak terpikirkan di platform. Jika beberapa kerangka kerja populer digunakan untuk membuat layanan - Symfony, Laravel, Yii atau yang lainnya - maka bahkan pengembang biasa-biasa saja akan menghindari sebagian besar masalah keamanan, karena ORM dapat menyiapkan kueri ke database, mesin templat dapat meng-endcode konten yang diterima dari pengguna, dan formulir dilindungi secara default dengan token CSRF, dan otorisasi serta otentikasi biasanya tersedia hampir di luar kotak. Dalam kasus yang sama, platform tersebut membuat pengembang kami bernostalgia dengan hari-hari mahasiswa - kodenya terlihat hampir sama dengan pekerjaan lab pertamanya di universitas.



Misalnya, berikut ini bagaimana koneksi database diimplementasikan. Kredensial koneksi di-hardcode di atas dalam file yang sama.



if (!isset($db)) {
	$db = new mysqli($db_info['host'], $db_info['user'], $db_info['pass'], $db_info['db']);
	if ($db->connect_errno) {
		die("Failed to connect to MySQL: " . $db->connect_errno);
	}
	if (!$db->set_charset("utf8")) {
		die("Error loading character set utf8 for MySQL: " . $db->connect_errno);
	}
	$db->autocommit(false);
}
      
      





2. Ada banyak masalah keamanan di platform



Setelah audit, kami menyadari bahwa dengan kekurangan seperti itu, tidak mungkin untuk berproduksi bahkan dengan blog sederhana, apalagi dengan platform dengan data rahasia. Ini beberapa di antaranya.



  • Injeksi SQL. 90% dari permintaan termasuk data yang dimasukkan oleh pengguna tanpa persiapan awal.



    $sql = "
    	UPDATE user
    	SET firstname='%s', lastname='%s', born='%s', prefix='%s', phone='%s', country_res='%s', extra=%s
    	WHERE id=%d
    ;";
    $result = $db->query(sprintf($sql,
    	$_POST['firstname'],
    	$_POST['lastname'],
    	$_POST['born'],
    	$_POST['prefix'],
    	$_POST['phone'],
    	$_POST['country'],
    	isset($_POST['extra']) ? "'".$_POST['extra']."'" : "NULL",
    	$_SESSION['user']['id']
    ));
          
          



  • Kerentanan XSS. Kode khusus tidak difilter dengan cara apa pun sebelum keluaran:



    <button id="btn-doc-password" class="btn btn-primary btn-large pull-right" data-action="<?= $_GET['action'] ?>"><i class="fas fa-check"></i> <?= _e("Valider") ?></button>
          
          





    Selain itu, informasi yang masuk ke database, seperti alasan berkonsultasi dengan dokter, tidak disaring baik sebelum ditulis ke database atau sebelum ditampilkan di halaman.
  • . ID , . . , ID .
  • . , -. , qury-string .



    $file_dir = $settings['documents']['dir'] . $_SESSION['client']['id'] . DIRECTORY_SEPARATOR . $_GET['id_user'];
          
          



  • Pustaka pihak ketiga yang kedaluwarsa. Di vendor lama, tidak ada yang mengikuti versi pustaka pihak ketiga, yang, ngomong-ngomong, alih-alih menggunakan Composer yang sama, cukup disalin ke dalam proyek. Selain itu, beberapa dependensi pihak ketiga ini telah disesuaikan.
  • Penyimpanan kata sandi pengguna yang tidak aman. Fungsi kriptografi yang tidak dapat diandalkan digunakan untuk menyimpan kata sandi.



    $sql = "
    	SELECT id, firstname, lastname
    	FROM user
    	WHERE id=%d AND password=PASSWORD('%s')
    ;";
    $result = $db->query(sprintf($sql, $_SESSION['user']['id'], $_POST['pass']));
          
          



  • Kerentanan CSRF. Tidak ada formulir yang diamankan dengan token CSRF.
  • Kurangnya perlindungan terhadap serangan brute force. Itu tidak ada di sana. Tidak.


Di sini kita dapat melanjutkan dan melanjutkan, tetapi masalah ini cukup untuk dipahami: apakah sistem memiliki masalah yang serius, atau sistem itu sendiri merupakan masalah yang serius.



3. Kode sulit untuk dipertahankan dan diperluas



Masalah keamanan tidak terbatas pada semuanya. Yang mengejutkan kami, proyek ini tidak memiliki sistem kontrol versi. Kode itu sama sekali tidak terstruktur. Direktori root dari server web berisi file seperti ajax-new.php, ajax2.php, dan semuanya digunakan dalam kode. Juga tidak ada penggambaran yang jelas ke dalam lapisan (presentasi, aplikasi, data). Dalam sebagian besar kasus, file kode adalah campuran PHP, HTML, dan JavaScript.



Semua ini mengarah pada fakta bahwa ketika kami diminta untuk membuat backoffice primitif untuk sistem ini, solusi terbaik adalah menerapkan Symfony 4 secara berdampingan dengan Sonata Admin dan tidak menyentuh kode yang ada sama sekali. Jelas bahwa jika kami diminta menambah kesempatan baru bagi dokter atau pasien, itu akan menyita banyak waktu dan energi kami. Dan karena tidak ada pembicaraan tentang tes otomatis, kemungkinan merusak sesuatu akan sangat tinggi.



Semua hal di atas sudah cukup bagi pemerintah Luksemburg - kami diberi lampu hijau untuk mengembangkan platform baru.



The Doctor Rides-Rides: Bagaimana Kami Mengembangkan Platform Baru



Kami mulai mempersiapkan pengembangan platform baru sejak awal - bahkan ketika kami melihat gagasan vendor lama. Oleh karena itu, ketika kami diberi izin untuk mengembangkan platform baru, kami segera mulai membuat versi MVP-nya. Sebuah tim yang terdiri dari empat PHP dan tiga pengembang front-end mengatasi tugas ini dalam waktu sekitar tiga setengah minggu. Semua pekerjaan dilakukan di Symfony 5, dan hanya panggilan video dan obrolan yang didelegasikan - semuanya diterapkan menggunakan layanan G-Core Meet kami. Kantor belakang untuk sistem lama juga berguna: kami berhasil menyesuaikannya dengan MVP hanya dalam beberapa hari. Hasilnya, versi MVP sistem mencakup 80% fungsionalitas platform lama. Sekarang, omong-omong, ini juga digunakan untuk satu tugas lagi - pada satu titik kami mengkloning MVP untuk meja bantuan badan kesehatan elektronik Luksemburg,sehingga administrator di sana dapat memanggil pengguna.



Ketika MVP sudah siap, kami mulai mengembangkan platform baru yang lengkap. Platform API dan ReactJS dalam hubungannya dengan Next.js untuk sisi klien digunakan sebagai dasar untuk API. Bukan tanpa tugas yang menarik.



1. Menerapkan pemberitahuan



Salah satu kesulitan muncul dengan notifikasi. Karena klien API dapat berupa aplikasi seluler dan SPA kami, diperlukan solusi gabungan.

Pertama, kami memilih Mercure Hub, tempat pelanggan berinteraksi melalui SSE (Server Sent Event). Tetapi tidak peduli bagaimana pembuat Platform API sendiri mempromosikan solusi ini, tim seluler kami menolaknya, karena aplikasi hanya dapat menerima pemberitahuan dalam keadaan aktif.



Inilah cara kami datang ke Firebase, yang dengannya kami berhasil mendapatkan dukungan untuk pemberitahuan push asli di perangkat seluler, dan keluar dari Mercure Hub untuk aplikasi browser. Sekarang, ketika suatu peristiwa terjadi di sistem, kami memberi tahu pengguna tentang hal itu melalui saluran pribadi yang kami butuhkan di Mercure Hub dan, sebagai tambahan, mengirimkan dorongan ke Firebase untuk perangkat seluler.



Mengapa kami tidak segera menerapkan semuanya di Firebase? Semuanya sederhana di sini: terlepas dari dukungan klien web, browser tanpa Push API - Safari yang sama dan sebagian besar browser seluler - tidak berfungsi dengannya. Namun, kami masih berencana untuk menerapkan notifikasi push dari Firebase untuk pengguna tersebut yang menggunakan browser yang didukung.



2. Tes fungsional



Situasi menarik lainnya muncul ketika kami melakukan uji fungsional untuk API. Seperti yang Anda ketahui, masing-masing harus bekerja di lingkungan yang bersih. Tetapi setiap kali ternyata mahal dalam hal kinerja untuk meningkatkan basis dan mengisi perlengkapan dasar + perlengkapan yang diperlukan untuk pengujian. Untuk menghindari hal ini, kami memutuskan pada tahap awal untuk meningkatkan database berdasarkan pemetaan entitas ( bin/console doctrine:schema:create



) dan baru kemudian menambahkan perlengkapan dasar ( bin/console doctrine:fixtures:load



).



Kemudian, dengan menggunakan ekstensi paket dama / doktrin-uji-uji, kami memastikan bahwa pelaksanaan setiap pengujian dibungkus dalam sebuah transaksi dan di akhir kasus uji memutar kembali tanpa berkomitmen. Karenanya, meskipun perubahan dilakukan ke database selama pengujian, perubahan tersebut tidak dilakukan, dan database setelah proses tetap berada dalam status yang sama seperti sebelum PHPUnit diluncurkan.

Agar setidaknya satu pengujian ditulis untuk setiap titik akhir, kami membuat pengujian peninjauan otomatis. Ini mendeteksi semua rute terdaftar dan memeriksa tes untuk mereka. Jadi, misalnya, untuk rute app_appointment_create, ia memeriksa apakah folder tersebut berisi tests/Functional/App/Appointment CreateTest.php



.



Selain itu, kualitas kode dipantau oleh PHP-CS-Fixer, php-cpd dan PHPStan dengan ekstensi seperti phpstan-strict-rules.



3. Sisi klien



Untuk dokter dan pasien, kami telah membuat dua aplikasi klien independen dengan UI yang sama dan kemampuan serupa. Untuk menggunakan kembali fungsionalitas dan UI di dalamnya, kami memutuskan untuk menggunakan monorepositori, yang mencakup pustaka dan aplikasi. Pada saat yang sama, aplikasi itu sendiri dibangun dan disebarkan secara independen satu sama lain, tetapi mungkin bergantung pada pustaka yang sama.



Pendekatan ini memungkinkan Anda membuat fitur (pustaka) dalam satu permintaan tarik dan mengintegrasikannya ke semua aplikasi yang Anda butuhkan. Keuntungan ini menyebabkan penggunaan monorepositori alih-alih mengimplementasikan fitur di pustaka dan proyek npm terpisah di repositori yang berbeda.

Untuk mengkonfigurasi monorepositori, pustaka ns.js digunakan, yang dari kotak memungkinkan Anda membangun pustaka dan aplikasi untuk React dan Next.js, dan tumpukan inilah yang digunakan dalam proyek. Kami menggunakan ESLint dan Prettier untuk melacak kualitas kode, Jest untuk menulis pengujian unit, dan Perpustakaan Pengujian React untuk menguji komponen React.



Dokter tiba: apa yang terjadi pada akhirnya



Hanya dalam lima bulan, semua masalah teratasi, dan platform baru tersedia untuk pengguna perangkat apa pun: kami menyiapkan versi web layanan, serta aplikasi seluler untuk iOS dan Android.



Selama lebih dari 4 bulan, layanan ini memungkinkan pasien menerima konsultasi online dari dokter dan dokter gigi. Mereka dapat berlangsung dalam format audio dan video. Akibatnya, dokter menulis resep dan dengan aman membagikan catatan medis dan hasil tes kepada pasien.



Platform ini tersedia untuk semua profesional perawatan kesehatan, penduduk, dan pekerja di Luksemburg. Sekarang dia bekerja di 2 dari institusi perawatan kesehatan terbesar di negara ini - di Rumah Sakit. Robert Schuman (Hรดpitaux Robert Schuman) dan Rumah Sakit Pusat. Emile Mayrisch (Pusat Hospitalier Emile Mayrisch). Layanan ini diterapkan di titik keberadaan yang aman dari cloud G-Core Labs di pusat data EDH Tier IV Luxembourg, tempat lingkungan virtual dikonfigurasikan untuknya sesuai dengan spesifikasi yang diperlukan.



All Articles