Keselamatan bagi kami bukanlah lapisan yang ditambah kemudian, tetapi teras seni bina. Pengasingan data, pemisahan identiti dan penulisan idempoten tertanam pada lapisan paling bawah kod — ia bukan tetapan yang boleh dimatikan, tetapi cara sistem berfungsi.
Pengasingan peringkat baris
Penulisan idempoten
Pertanyaan berparameter
Pengasingan loopback
Pengasingan data
Pengasingan peringkat baris — fail-closed
Pada setiap jadual berskop penyewa, PostgreSQL Row-Level Security FORCE diaktifkan; polisi mengikat setiap baris pada syarat "tenant_id = current_setting('app.current_tenant')".
Pertanyaan yang datang tanpa konteks penyewa ditetapkan memulangkan sifar baris — bukan sekadar ralat, tetapi kosong secara senyap. Melihat data satu klinik dengan sesi klinik lain adalah mustahil secara seni bina.
Ujian pengasingan silang penyewa adalah wajib hijau dalam integrasi berterusan (CI); jika merah, kod tidak digabungkan.
Penulisan atomik
Identiti transaction-local, transaksi atomik
Identiti penyewa ditetapkan pada PERMULAAN transaction dalam setiap operasi tulis dan hanya sah sepanjang transaction tersebut; ia tidak melekat pada kumpulan sambungan dan tidak bocor ke permintaan lain.
Operasi berbilang entiti (invois + item + pembayaran + penolakan stok) adalah atomik dalam satu transaction: sama ada semuanya ditulis bersama atau tiada satu pun. Tiada rekod separuh siap dan tidak tekal terhasil.
Kebenaran
Kebenaran berasaskan peranan (RBAC) dikuatkuasakan di pelayan
Kawalan kebenaran dilakukan pada lapisan API; klien atau bahagian hadapan tidak sekali-kali dipercayai. Menyembunyikan menu pada pelayar hanya berkaitan rupa — keputusan sebenar berada di pelayan.
Mutasi teras (Fasa 1) dilindungi mengikut peranan admin, setiausaha dan doktor. Walaupun peranan tanpa kebenaran memanggil titik akhir, permintaan itu ditolak.
Perlindungan ulangan
Penulisan idempoten — tiada transaksi berganda
Setiap permintaan penulisan membawa satu Idempotency-Key; kunci pada pihak pelayan menyekat transaksi kedua yang datang dengan kunci yang sama.
Walaupun rangkaian terputus atau klien menghantar semula permintaan yang sama, caj atau invois kedua tidak akan terhasil. Hasilnya sentiasa tunggal dan boleh diramal.
Keselamatan pertanyaan
SQL injection mustahil — pertanyaan berparameter
Semua pertanyaan pangkalan data ialah pernyataan berparameter sepenuhnya yang dijana pada masa penyusunan dengan sqlc. Dalam asas kod, tiada satu baris pun yang membina SQL dengan mencantumkan rentetan secara manual menggunakan input pengguna.
Ini menghapuskan kelas serangan SQL injection secara berstruktur — ia bergantung pada cara pertanyaan dibina, bukan pada usaha "penapisan" atau "pelepasan".
Permukaan rangkaian
Pengasingan loopback — teras tertutup kepada luar
API teras hanya mendengar pada 127.0.0.1 (loopback). Sebarang percubaan untuk terikat pada 0.0.0.0 atau IP awam ditolak semasa permulaan; teras tidak sekali-kali terdedah ke internet dalam apa jua keadaan.
Satu-satunya permukaan awam ialah pintu nipis (BFF): ia tidak menyimpan peraturan perniagaan selain sesi, render dan CSRF. Pelayar tidak pernah dapat melihat atau mengalamatkan API teras secara langsung.
Identiti & sesi
Kata laluan argon2id, kunci sesi opaque
Kata laluan di-hash menggunakan argon2id yang berat-memori dan menjadi standard industri; hash biasa atau lemah tidak digunakan.
Kunci sesi ialah nilai opaque kripto-rawak sebanyak 32 bait, disimpan dalam Redis dan luput dengan TTL. Hanya kuki HttpOnly + Secure + SameSite dipantulkan ke pelayar; kunci tidak pernah didedahkan kepada JavaScript.
Audit
Rekod audit tak boleh ubah (append-only)
Operasi penting ditulis ke dalam rekod audit append-only dalam transaction yang SAMA dengan mutasi yang mencetuskannya. Jika transaksi dibatalkan, rekod audit juga tidak ditulis — kedua-duanya tidak boleh dipisahkan.
Kebenaran UPDATE/DELETE telah ditarik daripada jadual audit; rekod tidak boleh disunting atau dipadam kemudian. Sejarah kekal sebagaimana adanya.
Privasi
Penopengan data sensitif
TCKN, kata laluan, kunci sesi dan data kesihatan tidak sekali-kali masuk ke dalam log. Medan ini ditopeng walaupun dalam output nyahpepijat.
Apabila diperlukan, medan sensitif disulitkan pada peringkat lajur. Data kesihatan bersifat sensitif khas dilindungi dengan peraturan yang diletakkan dalam reka bentuk sejak awal.
Integriti wang
Keselamatan wang — numeric, kemasukan balik
Wang disimpan di mana-mana dengan numeric(14,2); pengiraan wang tidak dilakukan dengan float. Pembundaran berlaku pada satu titik sahaja, di pelayan — tiada anjakan sen atau perbezaan pembundaran terhasil.
Pembatalan dan bayaran balik diproses sebagai kemasukan balik dan bukannya memadam rekod. Baki akaun tidak ditulis secara manual; ia sentiasa diterbitkan daripada jumlah invois dan pembayaran. Sejarah tidak dirosakkan.
Pemindahan
Pemindahan & keselamatan pelayar
Semua trafik dibawa melalui HTTPS/TLS dan HSTS diaktifkan; pelayar hanya membina sambungan secara disulitkan.
Polisi keselamatan kandungan (CSP) yang ketat menyekat skrip inline; X-Frame-Options DENY menghalang clickjacking, X-Content-Type-Options nosniff menghalang percampuran jenis. Referrer-Policy dan Permissions-Policy turut dikuatkuasakan.
Penting
Pemisahan tier identiti + satah pentadbiran berasingan
Pengguna klinik, portal pesakit dan pengendali-platform ialah tier identiti yang BERASINGAN: tajuk berasingan, ruang sesi berasingan. Kunci satu tier tidak berfungsi pada tier lain — sempadan kebenaran dipisahkan dengan tegas.
Hujung platform dan pentadbiran (penyediaan penyewa, pengebilan, pengurusan automasi/pemalam, penjanaan kunci API) TIDAK WUJUD dalam API awam.
Fungsi ini beroperasi pada satah kawalan berasingan, dalaman, dengan corak identiti berbeza (kunci pentadbiran khas); ia tidak boleh dicapai atau ditemui dari luar. Dengan itu, permukaan serangan mengecil dengan ketara.
CARA IA BERFUNGSI
Satu transaksi, pengasingan fail-closed
Aliran konsep di bawah menunjukkan bagaimana setiap penulisan dikunci kepada penyewa dan kekal idempoten. Ia hanya untuk tujuan penerangan.
# 1) Konteks penyewa disediakan pada PERMULAAN transaction (khusus untuk tx ini sahaja)
BEGIN;
SELECT set_config('app.current_tenant', :session_tenant_id, true);
# 2) Kunci Idempotency-Key — transaksi kedua dengan kunci yang sama tidak akan terhasilSELECT lock_idempotency(:idempotency_key);
# 3) Tulis pelbagai-entiti — semuanya atomik dalam satu txINSERT INTO invoices ...; # RLS: tenant_id diliputi automatikINSERT INTO payments ...;
INSERT INTO audit_log ...; # append-only, tx yang sama
COMMIT;
# Jika konteks tidak ditetapkan, dasar RLS tidak memulangkan sebarang baris:SELECT * FROM patients; --> 0 baris (bukan ralat, kosong secara senyap)
Boleh disahkan secara bebas
Sebahagian daripada keselamatan pemindahan boleh diperhatikan dari luar: anda sendiri boleh memeriksa sijil HTTPS/TLS pada sambungan anda, serta pengepala keselamatan respons seperti HSTS dan dasar keselamatan kandungan, melalui alat pembangun pelayar anda. Dakwaan kami berlandaskan kawalan seni bina, bukan ayat pemasaran.
Ada soalan tentang seni bina keselamatan?
Pasukan kami berbesar hati untuk membincangkan butiran teknikal dan keperluan pematuhan anda bersama anda.