MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

Zabezpieczanie MongoDB przed atakami z zewnętrznego wstrzykiwania

Bezpieczeństwo MongoDB nie jest w pełni gwarantowane przez zwykłą konfigurację certyfikatów uwierzytelniających lub szyfrowanie danych. Niektórzy atakujący pójdą o krok dalej, bawiąc się otrzymanymi parametrami w żądaniach HTTP, które są wykorzystywane jako część procesu zapytania bazy danych.

Bazy danych SQL są najbardziej podatne na tego typu ataki, ale zewnętrzne wstrzyknięcie jest również możliwe w bazach danych NoSQL, takich jak MongoDB. W większości przypadków zewnętrzne wstrzyknięcia mają miejsce w wyniku niebezpiecznego łączenia ciągów podczas tworzenia zapytań.

Co to jest atak z zewnętrznego wstrzyknięcia?

Wstrzykiwanie kodu to w zasadzie integracja niesprawdzonych danych (nieograniczonych wektorów) z podatnym programem, który po uruchomieniu prowadzi do katastrofalnego dostępu do bazy danych; zagrażające jego bezpieczeństwu.

Gdy nieoczyszczone zmienne są przekazywane do zapytania MongoDB, łamią one strukturę orientacji zapytania dokumentu i czasami są wykonywane jako sam kod javascript. Dzieje się tak często przy przekazywaniu props bezpośrednio z modułu body-parser dla serwera Nodejs. Dlatego osoba atakująca może łatwo wstawić obiekt Js w miejscu, w którym można się spodziewać ciągu lub liczby, uzyskując w ten sposób niepożądane wyniki lub manipulując danymi.

Rozważ poniższe dane w kolekcji ucznia.

{username:'John Doc', email:'[email protected]', age:20},

{username:'Rafael Silver', email:'[email protected]', age:30},

{username:'Kevin Smith', email:'[email protected]', age:22},

{username:'Pauline Wagu', email:'[email protected]', age:23}

Powiedzmy, że Twój program musi pobierać wszystkich uczniów w wieku 20 lat. Napisałbyś taki kod...

app.get(‘/:age’, function(req, res){

  db.collections(“students”).find({age: req.params.age});

})

W żądaniu http prześlesz obiekt JSON jako 

{age: 20}

Zwróci to wszystkich uczniów w wieku 20 lat jako oczekiwany wynik i tylko w tym przypadku {username:'John Doc', email:'[email protected]', age:20} .

Załóżmy teraz, że atakujący przesyła obiekt zamiast liczby, tj. {‘$gt:0’};

Wynikowe zapytanie to:

db.collections("studenci").find({wiek:{'$gt:0'}); które jest prawidłowym zapytaniem, które po wykonaniu zwróci wszystkich uczniów w tej kolekcji. Atakujący ma szansę działać na Twoich danych zgodnie ze swoimi złośliwymi intencjami. W większości przypadków atakujący wstrzykuje niestandardowy obiekt, który zawiera polecenia MongoDB, które umożliwiają mu dostęp do Twoich dokumentów bez odpowiedniej procedury.

Niektóre polecenia MongoDB wykonują kod JavaScript w silniku bazy danych, co stanowi potencjalne zagrożenie dla danych. Niektóre z tych poleceń to „$where”, „$group” i „mapReduce”. W przypadku wersji wcześniejszych niż MongoDB 2.4 kod Js ma dostęp do obiektu db z poziomu zapytania.

Natywna ochrona MongoDB

MongoDB wykorzystuje dane BSON (binarny JSON) zarówno dla swoich zapytań, jak i dokumentów, ale w niektórych przypadkach może akceptować niezserializowane wyrażenia JSON i Js (takie jak te wymienione powyżej). Większość danych przekazywanych do serwera jest w formacie ciągu i można je wprowadzić bezpośrednio do zapytania MongoDB. MongoDB nie analizuje swoich danych, dzięki czemu unika się potencjalnych zagrożeń, które mogą wynikać z integracji bezpośrednich parametrów.

Jeśli interfejs API wymaga kodowania danych w sformatowanym tekście i tekst ten musi zostać przeanalizowany, może to spowodować niezgodność między wywołującym serwer a wywoływaną bazą danych co do tego, jak ten ciąg ma być analizowany . Jeśli dane zostaną przypadkowo błędnie zinterpretowane jako metadane, scenariusz może potencjalnie stanowić zagrożenie dla bezpieczeństwa Twoich danych.

Przykłady zewnętrznych wstrzyknięć MongoDB i sposoby ich obsługi

 Rozważmy poniższe dane w zbiorze uczniów.

{username:'John Doc', password: ‘16djfhg’, email:'[email protected]', age:20},

{username:'Rafael Silver',password: ‘djh’, email:'[email protected]', age:30},

{username:'Kevin Smith', password: ‘16dj’, email:'[email protected]', age:22},

{username:'Pauline Wagu', password: ‘g6yj’, email:'[email protected]', age:23}

Wstrzykiwanie za pomocą operatora $ne (nie równego)

Jeśli chcę zwrócić dokument z nazwą użytkownika i hasłem podanym w żądaniu, kod będzie wyglądał następująco:

app.post('/students, function (req, res) {

    var query = {

        username: req.body.username,

        password: req.body.password

    }

    db.collection(students).findOne(query, function (err, student) {

        res(student);

    });

});

Jeśli otrzymamy poniższe żądanie

POST https://localhost/students HTTP/1.1

Content-Type: application/json

{

    "username": {"$ne": null},

    "password": {"$ne": null}

}

W tym przypadku zapytanie z pewnością zwróci pierwszego ucznia, ponieważ jego nazwa użytkownika i hasło nie mają wartości NULL. Nie jest to zgodne z oczekiwanymi wynikami.

Aby rozwiązać ten problem, możesz użyć:

moduł mongo-sanitize, który zatrzymuje każdy klucz zaczynający się od „$” przed przekazaniem do silnika zapytań MongoDB.

Najpierw zainstaluj moduł  

​npm install mongo-sanitize

var sanitize = require(‘mongo-sanitize’);

var query = {

username: req.body.username,

password: req.body.password

}

Używanie mangusty do sprawdzania poprawności pól schematu tak, że jeśli oczekuje ciągu i odbierze obiekt, zapytanie wygeneruje błąd. W naszym przypadku powyżej wartość null zostanie przekonwertowana na ciąg znaków „”, który dosłownie nie ma żadnego wpływu.

Wstrzykiwanie za pomocą operatora $where

To jeden z najniebezpieczniejszych operatorów. Pozwoli to na ocenę ciągu wewnątrz samego serwera. Na przykład, aby pobrać uczniów, których wiek przekracza wartość Y, zapytanie będzie wyglądać tak: 

var query = { 

   $where: “this.age > ”+req.body.age

}

 db.collection(students).findOne(query, function (err, student) {

        res(student);

    });

Skorzystanie z modułu sanitize nie pomoże w tym przypadku, jeśli mamy ‘0; return true’, ponieważ wynik zwróci wszystkich uczniów, a nie tych, których wiek jest większy niż podana wartość. Inne możliwe ciągi, które możesz otrzymać, to „\”; return \ ‘\’ ==\’’ lub  this.email ===‘’;return ‘’ ==‘’. To zapytanie zwróci wszystkich uczniów, a nie tylko tych, którzy pasują do klauzuli.

Należy zdecydowanie unikać klauzuli $where. Oprócz opisanej wady zmniejsza to również wydajność, ponieważ nie jest zoptymalizowany do korzystania z indeksów.

Istnieje również duża możliwość przekazania funkcji w klauzuli $where, a zmienna nie będzie dostępna w zakresie MongoDB, co może spowodować awarię aplikacji. To znaczy

var query = {

   $where: function() {

       return this.age > setValue //setValue is not defined

   }

}

Możesz również użyć operatorów $eq, $lt, $lte, $gt, $gte.

Ochrona się przed zewnętrznym wstrzyknięciem MongoDB

Oto trzy rzeczy, które możesz zrobić, aby zapewnić sobie ochronę...

  1. Zweryfikuj dane użytkownika. Patrząc wstecz na to, jak wyrażenie $where może być używane do uzyskiwania dostępu do danych, zaleca się, aby zawsze sprawdzać, co użytkownicy wysyłają na serwer.
  2. Użyj koncepcji walidatora JSON, aby sprawdzić poprawność schematu wraz z modułem mangusta.
  3. Zaprojektuj swoje zapytania tak, aby kod Js nie miał pełnego dostępu do kodu Twojej bazy danych.

Wnioski

Z MongoDB możliwe są również wtryski zewnętrzne. Często wiąże się to z dostaniem się niesprawdzonych danych użytkownika do zapytań MongoDB. Zawsze ważne jest wykrywanie i zapobieganie wstrzykiwaniu NoSQL poprzez testowanie wszelkich danych, które mogą być odbierane przez Twój serwer. W przypadku zaniedbania może to zagrozić bezpieczeństwu danych użytkownika. Najważniejszą procedurą jest sprawdzenie poprawności danych we wszystkich zaangażowanych warstwach.


  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Migracja MongoDB do DynamoDB, część 2

  2. Tworzenie interfejsów API REST za pomocą EVE

  3. mongo:zwrot nie jest równy count()

  4. Grupuj według wartości i warunków

  5. Zapytanie Mongodb z polami w tych samych dokumentach