Dane często wymagają najwyższych zabezpieczeń na prawie każdym poziomie transakcji danych, aby zapewnić zgodność z zasadami bezpieczeństwa, zgodnością i przepisami rządowymi. Reputacja organizacji może zostać zrujnowana w przypadku nieuprawnionego dostępu do danych wrażliwych, a tym samym nieprzestrzegania nakreślonego mandatu.
W tym blogu będziemy omawiać niektóre środki bezpieczeństwa, które można zastosować w odniesieniu do MongoDB, szczególnie skupiając się na stronie klienta.
Scenariusze, w których można uzyskać dostęp do danych
Istnieje kilka sposobów, w jakie ktoś może uzyskać dostęp do Twoich danych MongoDB, oto kilka z nich...
- Przechwytywanie danych w niezabezpieczonej sieci. Ktoś może uzyskać dostęp do Twoich danych za pośrednictwem interfejsu API z siecią VPN i trudno będzie je wyśledzić. W tym przypadku często winowajcą są dane w spoczynku.
- Superużytkownik, taki jak administrator mający bezpośredni dostęp. Dzieje się tak, gdy nie zdefiniujesz ról i ograniczeń użytkowników.
- Mając dostęp do danych na dysku podczas odczytu baz danych plików kopii zapasowych.
- Odczytywanie pamięci serwera i zarejestrowanych danych.
- Przypadkowe ujawnienie danych przez członka personelu.
Kategorie danych MongoDB i sposób ich zabezpieczenia
Ogólnie rzecz biorąc, każdy system baz danych obejmuje dwa rodzaje danych:
- Dane w spoczynku:takie, które są przechowywane w plikach bazy danych
- Dane w drodze:takie, które są przesyłane między klientem, serwerem i bazą danych.
MongoDB ma funkcję szyfrowania w spoczynku, która szyfruje pliki bazy danych na dysku, co zapobiega dostęp do plików bazy danych na dysku.
Dane przesyłane przez sieć można zabezpieczyć w MongoDB za pomocą szyfrowania transportu przy użyciu TLS/SSL poprzez szyfrowanie danych.
W przypadku przypadkowego ujawnienia danych przez członka personelu, na przykład recepcjonistę, na ekranie komputera, MongoDB integruje kontrolę dostępu opartą na rolach, która umożliwia administratorom przyznawanie i ograniczanie uprawnień na poziomie kolekcji dla użytkowników.
Dane przesyłane przez serwer mogą pozostać w pamięci, a te podejścia w żadnym momencie nie rozwiązują problemu bezpieczeństwa przed dostępem do danych w pamięci serwera. Dlatego MongoDB wprowadził szyfrowanie na poziomie pola po stronie klienta do szyfrowania określonych pól dokumentu, które obejmują poufne dane.
Szyfrowanie na poziomie pola
MongoDB działa z dokumentami, które mają zdefiniowane pola. Niektóre pola mogą być wymagane do przechowywania poufnych informacji, takich jak numer karty kredytowej, numer ubezpieczenia społecznego, dane diagnozy cierpliwości i wiele innych.
Szyfrowanie na poziomie pola umożliwi nam zabezpieczenie pól, a dostęp do nich może uzyskać tylko upoważniony personel za pomocą kluczy deszyfrujących.
Szyfrowanie można wykonać na dwa sposoby
- Korzystanie z tajnego klucza. Pojedynczy klucz jest używany zarówno do szyfrowania, jak i odszyfrowywania, dlatego musi być prezentowany w transmisji źródłowej i docelowej, ale utrzymywany w tajemnicy przez wszystkie strony.
- Korzystanie z klucza publicznego. Używa pary kluczy, z których jeden służy do szyfrowania, a drugi do odszyfrowywania
Kiedy stosujesz szyfrowanie na poziomie pola, rozważ użycie nowej konfiguracji bazy danych zamiast istniejącej.
Szyfrowanie na poziomie pola po stronie klienta (CSFLE)
Wprowadzony w MongoDB w wersji 4.2 Enterprise, aby zaoferować administratorom baz danych dostosowanie szyfrowania pól zawierających wartości, które muszą być zabezpieczone. Oznacza to, że poufne dane są szyfrowane lub odszyfrowywane przez klienta i przekazywane do iz serwera tylko w postaci zaszyfrowanej. Poza tym nawet superużytkownicy, którzy nie mają kluczy szyfrowania, nie będą mieć kontroli nad tymi zaszyfrowanymi polami danych.
Jak wdrożyć CSFLE
W celu wdrożenia szyfrowania na poziomie pola po stronie klienta wymagane są następujące elementy:
- MongoDB Server 4.2 Enterprise
- MongoDB Zgodne z CSFLE
- Uprawnienia systemu plików
- Sterowniki dla określonych języków. (Na naszym blogu będziemy używać Node.js)
Procedura implementacji obejmuje:
- Lokalne środowisko programistyczne z oprogramowaniem do uruchamiania klienta i serwera
- Generowanie i weryfikowanie kluczy szyfrowania.
- Konfigurowanie klienta do automatycznego szyfrowania na poziomie pola
- Przez operacje w zakresie zapytań o zaszyfrowane pola.
Implementacja CSFLE
CSFLE korzysta ze strategii szyfrowania koperty, w której klucze szyfrowania danych są szyfrowane innym kluczem zwanym kluczem głównym. Aplikacja kliencka tworzy klucz główny, który jest przechowywany w lokalnym dostawcy kluczy, zasadniczo w lokalnym systemie plików. Jednak to podejście do przechowywania jest niepewne, dlatego w środowisku produkcyjnym zaleca się skonfigurowanie klucza w systemie zarządzania kluczami (KMS), który przechowuje i zdalnie odszyfrowuje klucze szyfrowania danych.
Po wygenerowaniu kluczy szyfrowania danych są one przechowywane w kolekcji skarbca w tym samym zestawie replik MongoDB, co zaszyfrowane dane.
Utwórz klucz główny
W węźle js musimy wygenerować 96-bajtowy klucz główny zarządzany lokalnie i zapisać go w pliku w katalogu, z którego wykonywany jest główny skrypt:
$npm install fs && npm install crypto
Następnie w skrypcie:
const crypto = require(“crypto”)
const fs = require(“fs”)
try{
fs.writeFileSync(‘masterKey.txt’, crypto.randomBytes(96))
}catch(err){
throw err;
}
Utwórz klucz szyfrowania danych
Ten klucz jest przechowywany w kolekcji magazynu kluczy, gdzie klienci z włączoną funkcją CSFLE mogą uzyskać dostęp do klucza w celu szyfrowania/odszyfrowywania. Aby go wygenerować, potrzebujesz:
- Lokalnie zarządzany klucz główny
- Połączenie z bazą danych, czyli ciąg połączenia MongoDB
- Przestrzeń nazw magazynu kluczy (baza danych i kolekcja)
Kroki generowania klucza szyfrowania danych
-
Odczytaj lokalny klucz główny wygenerowany przed
const localMasterKey = fs.readFileSync(‘./masterKey.txt’);
-
Określ ustawienia dostawcy KMS, które będą używane przez klienta do wykrywania klucza głównego.
const kmsProvider = {
local: {
key: localMasterKey
}
}
-
Tworzenie klucza szyfrowania danych. Musimy utworzyć klienta z parametrami połączenia MongoDB i konfiguracją przestrzeni nazw magazynu kluczy. Załóżmy, że będziemy mieć bazę danych o nazwie users, a w niej kolekcję keyVault. Musisz najpierw zainstalować uuid-base64, uruchamiając polecenie
$ npm install uuid-base64
Wtedy w twoim skrypcie
const base64 = require('uuid-base64');
const keyVaultNamespace = 'users.keyVaul';
const client = new MongoClient('mongodb://localhost:27017', {
useNewUrlParser: true,
useUnifiedTopology: true,
});
async function createKey() {
try {
await client.connect();
const encryption = new ClientEncryption(client, {
keyVaultNamespace,
kmsProvider,
});
const key = await encryption.createDataKey('local');
const base64DataKeyId = key.toString('base64');
const uuidDataKeyId = base64.decode(base64DataKeyId);
console.log('DataKeyId [UUID]: ', uuidDataKeyId);
console.log('DataKeyId [base64]: ', base64DataKeyId);
} finally {
await client.close();
}
}
createKey();
Następnie zostanie wyświetlony wynik przypominający
DataKeyId [UUID]: ad4d735a-44789-48bc-bb93-3c81c3c90824
DataKeyId [base64]: 4K13FkSZSLy7kwABP4HQyD==
Klient musi mieć uprawnienia do odczytu zapisu w określonej przestrzeni nazw magazynu kluczy
-
W celu sprawdzenia, czy utworzono klucz szyfrowania danych
const client = new MongoClient('mongodb://localhost:27017', {
useNewUrlParser: true,
useUnifiedTopology: true,
});
async function checkClient() {
try {
await client.connect();
const keyDB = client.db(users);
const keyColl = keyDB.collection(keyVault);
const query = {
_id: ‘4K13FkSZSLy7kwABP4HQyD==’,
};
const dataKey = await keyColl.findOne(query);
console.log(dataKey);
} finally {
await client.close();
}
}
checkClient();
Powinieneś otrzymać jakiś wynik tego rodzaju
{
_id: Binary {
_bsontype: 'Binary',
sub_type: 4,
position: 2,
buffer: <Buffer 68 ca d2 10 16 5d 45 bf 9d 1d 44 d4 91 a6 92 44>
},
keyMaterial: Binary {
_bsontype: 'Binary',
sub_type: 0,
position: 20,
buffer: <Buffer f1 4a 9f bd aa ac c9 89 e9 b3 da 48 72 8e a8 62 97 2a 4a a0 d2 d4 2d a8 f0 74 9c 16 4d 2c 95 34 19 22 05 05 84 0e 41 42 12 1e e3 b5 f0 b1 c5 a8 37 b8 ... 110 more bytes>
},
creationDate: 2020-02-08T11:10:20.021Z,
updateDate: 2020-02-08T11:10:25.021Z,
status: 0,
masterKey: { provider: 'local' }
}
Zwrócone dane dokumentu obejmują:identyfikator klucza szyfrowania danych (UUID), klucz szyfrowania danych w postaci zaszyfrowanej, informacje dostawcy KMS o kluczu głównym i metadane, takie jak dzień tworzenie.
Określanie pól do zaszyfrowania za pomocą schematu JSON
Rozszerzenie schematu JSON jest używane przez sterowniki MongoDB do konfigurowania automatycznego szyfrowania i odszyfrowywania po stronie klienta określonych pól dokumentów w kolekcji. Konfiguracja CSFLE dla tego schematu będzie wymagać:algorytmu szyfrowania używanego podczas szyfrowania każdego pola, jednego lub wszystkich kluczy szyfrowania zaszyfrowanych za pomocą klucza głównego CSFLE oraz typu BSON każdego pola.
Jednak ten schemat CSFLE JSON nie obsługuje walidacji dokumentów, w przeciwnym razie wszelkie instancje walidacji spowodują zgłoszenie przez klienta błędu.
Klientom, którzy nie skonfigurowano odpowiedniego schematu JSON po stronie klienta, można ograniczyć możliwość zapisywania niezaszyfrowanych danych w polu przy użyciu schematu JSON po stronie serwera.
Istnieją głównie dwa algorytmy szyfrowania:losowy i deterministyczny.
Zdefiniujemy klucz encryptMetadata na poziomie głównym schematu JSON i skonfigurujemy go z polami do zaszyfrowania, definiując je w polu właściwości schematu, dzięki czemu będą mogli odziedziczyć ten klucz szyfrowania .
{
"bsonType" : "object",
"encryptMetadata" : {
"keyId" : // keyId generated here
},
"properties": {
// field schemas here
}
}
Powiedzmy, że chcesz zaszyfrować pole numeru konta bankowego, zrobiłbyś coś takiego:
"bankAccountNumber": {
"encrypt": {
"bsonType": "int",
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
}
}
Ze względu na dużą kardynalność i pole, które można odpytywać, stosujemy podejście deterministyczne. Pola wrażliwe, takie jak grupa krwi, które mają niski plan zapytań i niską kardynalność, mogą być szyfrowane metodą losową.
Pola tablicy powinny używać losowego szyfrowania za pomocą CSFLE, aby usprawnić automatyczne szyfrowanie dla wszystkich elementów.
Aplikacja Mongocryptd
Zainstalowana w MongoDB Enterprise Service 4.2 i nowszych, jest to oddzielna aplikacja szyfrująca, która automatyzuje szyfrowanie na poziomie pola po stronie klienta. Za każdym razem, gdy tworzony jest klient z włączoną obsługą CSFLE, ta usługa jest domyślnie uruchamiana automatycznie w następujący sposób:
- Weryfikuj instrukcje szyfrowania opisane w schemacie JSON, wykrywaj, które pola mają być zaszyfrowane w operacjach przepustowości.
- Zapobiegaj wykonywaniu nieobsługiwanych operacji na zaszyfrowanych polach.
Aby wstawić dane, wykonamy normalne zapytanie wstawiania, a wynikowy dokument będzie zawierał przykładowe dane poniżej w odniesieniu do pola konta bankowego.
{
…
"bankAccountNumber":"Ac+ZbPM+sk7gl7CJCcIzlRAQUJ+uo/0WhqX+KbTNdhqCszHucqXNiwqEUjkGlh7gK8pm2JhIs/P3//nkVP0dWu8pSs6TJnpfUwRjPfnI0TURzQ==",
…
}
Gdy upoważniony personel wykona zapytanie, kierowca odszyfruje te dane i zwróci je w czytelnym formacie, tj.
{
…
"bankAccountNumber":43265436456456456756,
…
}
Uwaga: nie można wyszukiwać dokumentów w losowo zaszyfrowanym polu, chyba że użyjesz innego pola do znalezienia dokumentu, który zawiera przybliżone dane z losowo zaszyfrowanych pól.
Wnioski
Bezpieczeństwo danych powinno być brane pod uwagę na wszystkich poziomach w odniesieniu do jednego w spoczynku i tranzycie. MongoDB Enterprise 4.2 Server oferuje programistom okno do szyfrowania danych po stronie klienta za pomocą szyfrowania na poziomie pola po stronie klienta, zabezpieczając w ten sposób dane od dostawców hosta bazy danych i niezabezpieczony dostęp do sieci. CSFLE używa szyfrowania kopertowego, gdzie klucz główny jest używany do szyfrowania kluczy szyfrowania danych. Dlatego klucz główny powinien być bezpieczny przy użyciu narzędzi do zarządzania kluczami, takich jak system zarządzania kluczami.