Jak przeszukiwać bazę danych MySQL z zaszyfrowanymi polami

15

Załóżmy, że trzeba zaszyfrować pewne tabeli pól o MySQL bazy danych. Ponadto muszę przeszukać niektóre z pól , które szyfrowałem.

Jak i tak przeszukać te pola?

Odszyfrowanie każdego rekordu krok po kroku nie jest opcją: Załóżmy, że mam wiele tysięcy rekordów. Odszyfrowanie każdego rekordu i sprawdzenie, czy każdy rekord pasuje do wyszukiwania, zajęłoby zbyt dużo czasu i miejsca.

AKTUALIZACJA 2012-09-07

Dodanie dalszych szczegółów do schematu bazy danych byłoby OK , ponieważ zamierzam wdrożyć nową aplikację. Ponadto muszę rozszerzyć aplikacje aktualnie uruchomione w produkcji. Ale nawet w przypadku tych aplikacji dodanie dalszych szczegółów byłoby OK.

AKTUALIZACJA 08.09.2012

Szyfrowanie jest jądrem tego pytania.

Ograniczenia dostępu, jak sugerują niektóre odpowiedzi, już obowiązują - ale nie spełniają formalnego wymogu szyfrowania danych.

Ten formalny wymóg nie jest standardem bezpieczeństwa danych branżowych kart płatniczych [PCI].

SteAp
źródło

Odpowiedzi:

11

Oczywiście nie należy ich oglądać, dlatego ich wyszukiwanie byłoby problematyczne.

Jedną sztuczką, której użyłem w przeszłości, jest mieszanie zaszyfrowanych danych przed ich zaszyfrowaniem i przechowywanie skrótu w indeksowanej kolumnie. Oczywiście działa to tylko wtedy, gdy szukasz całej wartości; wartości częściowe nie będą miały tego samego skrótu.

Prawdopodobnie możesz to rozszerzyć, tworząc indeks skrótów „pełnego tekstu”, jeśli zajdzie taka potrzeba, ale może się to bardzo szybko skomplikować.

UZUPEŁNIENIE

Sugeruje się dodanie przypisu do mojej odpowiedzi podczas dość długiej debaty na czacie na temat podatności na ataki słownikowe, dlatego omówię potencjalne zagrożenie bezpieczeństwa dla powyższego podejścia.

Atak słownikowy: Atak słownikowy ma miejsce, gdy ktoś wstępnie hashuje listę znanych wartości i porównuje skróty z kolumną haszowaną w bazie danych. Jeśli uda im się znaleźć dopasowanie, prawdopodobne jest, że znana wartość jest faktycznie tym, co jest haszowane (Nie jest to jednak jednoznaczne, ponieważ skróty nie są gwarantowane jako unikalne). Zazwyczaj jest to łagodzone przez haszowanie wartości z dołączoną lub dodaną losową „solą”, aby skrót nie pasował do słownika, ale powyższa odpowiedź nie może użyć soli, ponieważ utracisz możliwość wyszukiwania.

Ten atak jest niebezpieczny w przypadku takich haseł: jeśli utworzysz słownik popularnych skrótów haseł, możesz szybko przeszukać tabelę pod kątem tej wartości skrótu i ​​zidentyfikować użytkownika, który ma takie hasło, i skutecznie wyodrębnić dane uwierzytelniające w celu kradzieży tożsamości tego użytkownika .

Jest mniej niebezpieczny dla przedmiotów o wysokim stopniu liczności, takich jak numery SSN, numery kart kredytowych, identyfikatory GUID itp. (Ale istnieją różne rodzaje ryzyka związane z ich przechowywaniem, więc nie jestem skłonny doradzać w sprawie ich przechowywania ).

Powodem tego jest, aby atak słownikowy zadziałał, musisz mieć wstępnie zbudowany słownik możliwych wartości i ich skrótów. Teoretycznie możesz zbudować słownik wszystkich możliwych SSN (miliard wierszy, zakładając, że wszystkie permutacje formatowania zostaną usunięte; kilkadziesiąt bilionów wpisów dla kart kredytowych) ... ale to zwykle nie jest celem ataku słownikowego i w zasadzie staje się porównywalny z atakiem brutalnej siły, w którym systematycznie badasz każdą wartość.

Możesz także poszukać określonego numeru SSN lub numeru karty kredytowej, jeśli próbujesz dopasować SSN do konkretnej osoby. Ponownie, zwykle nie jest to cel ataku słownikowego, ale możliwe do zrobienia, więc jeśli jest to ryzyko, którego należy unikać, moja odpowiedź nie jest dla ciebie dobrym rozwiązaniem.

Więc masz to. Podobnie jak w przypadku wszystkich zaszyfrowanych danych, zwykle są one szyfrowane z jakiegoś powodu, więc bądź świadomy swoich danych i tego, przed czym chcesz je chronić.

Jeremy Holovacs
źródło
Dyskusja na temat tej odpowiedzi została przeniesiona do czatu .
Paul White 9
5

Możesz rzucić okiem na CryptDB . Jest to interfejs dla MySQL i PostgreSQL, który umożliwia przejrzyste przechowywanie i wyszukiwanie zaszyfrowanych danych. Działa poprzez szyfrowanie i deszyfrowanie danych przesyłanych między aplikacją a bazą danych, przepisując zapytania w celu działania na zaszyfrowanych danych. oraz dynamicznie dostosowując tryb szyfrowania każdej kolumny, aby wyświetlać tylko tyle informacji, ile jest potrzebne do zapytań używanych przez aplikację.

Różne metody szyfrowania stosowane przez CryptDB obejmują:

  • RND , w pełni bezpieczny schemat szyfrowania IND-CPA, który nie przecieka żadnych informacji o danych (z wyjątkiem ich obecności i, w przypadku typów o zmiennej długości, długości), ale umożliwia jedynie przechowywanie i pobieranie, bez zapytań.

  • DET , wariant RND, który jest deterministyczny, dzięki czemu dwie identyczne wartości (w tej samej kolumnie) są szyfrowane do tego samego tekstu zaszyfrowanego. Obsługuje zapytania dotyczące równości formularza WHERE column = 'constant'.

  • OPE , schemat szyfrowania zachowujący porządek, który obsługuje zapytania o nierówności, takie jak WHERE column > 'constant'.

  • HOM , częściowo homomorficzny schemat szyfrowania (Paillier), który umożliwia dodawanie zaszyfrowanych wartości razem przez pomnożenie tekstów zaszyfrowanych. Obsługuje SUM()zapytania, dodawanie i zwiększanie.

  • SZUKAJ , schemat, który obsługuje wyszukiwanie słów kluczowych w formularzu WHERE column LIKE '% word %'.

  • JOIN i OPE-JOIN , warianty DET i OPE, które umożliwiają porównywanie wartości w różnych kolumnach. Obsługuje odpowiednio połączenia równości i zasięgu.

Prawdziwą mocą CryptDB jest to, że dynamicznie dostosowuje metodę szyfrowania każdej kolumny do zapytań, które widzi, dzięki czemu wolniejsze i / lub mniej bezpieczne schematy są używane tylko dla kolumn, które ich wymagają. Istnieją również różne inne przydatne funkcje, takie jak łączenie kluczy szyfrujących z hasłami użytkowników.

Jeśli jesteś zainteresowany, dobrze jest zapoznać się z dokumentami powiązanymi ze stroną CryptDB, w szczególności „CryptDB: Ochrona poufności za pomocą szyfrowanego przetwarzania zapytań” Popa, Redfield, Zeldovich i Balakrishnan ( SOSP 2011 ). Dokumenty te opisują również bardziej szczegółowo różne kompromisy w zakresie bezpieczeństwa i wydajności związane z obsługą różnych typów zapytań.

Ilmari Karonen
źródło
1
It works by encrypting and decrypting data as it passes between the application and the database: Z pewnością może to powodować problemy, jeśli wyszukiwane dane są już w bazie danych (zaszyfrowane), ale oczywiście samo zapytanie przeszukujące bazę danych jest następnie przekazywane do CryptDB (a następnie szyfrowane?). Nie rozumiem, jak ta metoda może być w ogóle skuteczna?
Martin
3

Nie rozumiem, dlaczego obecne odpowiedzi nie zakwestionowały w pełni wymagań, więc zapytam i zostawię jako odpowiedź.

Jakie są przyczyny biznesowe? Jakie dane potrzebujesz zaszyfrować i dlaczego? Jeśli szukasz zgodności z PCI, mógłbym napisać esej.

Pytania dotyczące twojego wymagania:

  • Czy musisz zwrócić wynik istnieje / nie istnieje w wyniku lub rzeczywiste dane?
  • Czy potrzebujesz funkcji LIKE „% OMG_SEKRIT%”?
  • Kto nie widzi danych i dlaczego?

Zabezpieczenia RDBMS są zwykle wykonywane na podstawie uprawnień, które są wymuszane przez użytkownika / rolę. Dane są zwykle szyfrowane przez RDBMS na dysku, ale nie w samych danych kolumnowych, ponieważ tak naprawdę nie ma to sensu dla aplikacji zaprojektowanej do wydajnego przechowywania i pobierania danych.

Ogranicz według użytkownika / roli / interfejsu API. Szyfruj na dysku. Jeśli przechowujesz ważniejsze dane, chciałbym wiedzieć, dlaczego używasz MySQL.

Philᵀᴹ
źródło
Przede wszystkim muszę znaleźć istnieje / nie istnieje, a następnie zlokalizować konkretny rekord. Pełne wsparcie LIKE byłoby w porządku. Zastanawiam się jednak, że możliwe będzie coś więcej niż dopasowanie słów. Upoważnieni użytkownicy mogą wyświetlać dane. Aplikacja odszyfrowuje te elementy, legalny użytkownik ma prawo do ich przeglądania. Schematy bazowe uprawnień nie są opcją.
SteAp
Jakie są kryteria dla „ważniejszych danych?”
arcanine,
2

Patrzę na to i natknąłem się na twoje pytanie. Opieram się na podejściu przedstawionym w sekcji 5.4 dokumentu „Praktyczne techniki wyszukiwania w zaszyfrowanych danych” http://www.cs.berkeley.edu/~dawnsong/papers/se.pdf

Podstawowym założeniem jest utworzenie indeksu zawierającego zaszyfrowane słowa kluczowe, które są obecne w zaszyfrowanym dokumencie wyszukiwania. Sztuką jest także szyfrowanie lokalizacji w dokumencie (lub bazie danych), w których obecne są te słowa kluczowe.

M. Scott Ford
źródło
1

Programowo skutecznym rozwiązaniem jest

  1. pobierz WSZYSTKIE rekordy TYLKO dla pola, którego szukasz, używając identyfikatora rekordu
  2. odszyfruj je do tabeli tymczasowej
  3. przeprowadź wyszukiwanie dla tej tabeli
  4. użyj identyfikatorów, aby pobrać pełne rekordy (wszystkie pola), które spełniają kryteria wyszukiwania
  5. odszyfruj je i zwróć użytkownikowi

Chodzi o to, że 1 i 4 są znacznie mniejszymi zestawami danych niż pobieranie i deszyfrowanie wszystkich pól wszystkich rekordów na początku.

Mam nadzieję, że to pomaga.

Paul B. Hartzog
źródło
Tabele tymczasowe w postaci zwykłego tekstu są względnie (tj. Bardzo) łatwe do pobrania i odczytania, zakłócają działanie serwera w odpowiednim momencie lub po prostu kopiują temp/folder i wybijają, wartości tekstu jawnego dla całej kolumny są dostępne, nie jest to bezpieczny sposób działania
Martin
1

Jest to możliwe dzięki pełnej funkcjonalności wyszukiwania przy użyciu wewnętrznych funkcji szyfrowania MYSQL.

Oto przykład:

!!! UŻYWAM KODU MYSQL () TUTAJ DLA PROSTOŚCI, MYSQL_ENCODE JEST TERAZ UWAŻANY ZA BEZPIECZEŃSTWO, NALEŻY UŻYWAĆ JEDNEGO Z INNYCH WEWNĘTRZNYCH FUNKCJI MYSQL !!!

UPDATE my_table
SET field=ENCODE('my_data', 'my_password')
WHERE ID=1;

SELECT DECODE(field, 'my_password') as field FROM my_table
WHERE field LIKE 'data';

Jak sugeruje powyższy komentarz, NIE używaj ENCODE (), używaj jednej z innych funkcji szyfrowania Używam tylko ENCODE w tym przykładzie ze względu na jego prostotę

Jeśli robisz to w aplikacji, takiej jak php, możesz to zrobić w ramach bramy db lub klas repozytorium, przechowując listę / tablicę zaszyfrowanych kolumn każdej tabeli w odpowiedniej klasie bramy.

class UserGateway
{
    protected $encrypted_fields = array(
        'username',
        'email'
    );

    public function get($fields, ...)
    {
        foreach ($fields as $k => $field) {
            if (in_array($field, $fields)) {
                $fields[$k] = $this->decodeSelect($field);
            }
        }

        $sql = 'SELECT '.implode(',', $fields);

        //......
    }

    protected function decodeSelect($field)
    {
        return "DECODE($field, $pass) AS $field";
    }
}

Oczywiście jest to bardzo szorstki i niepewny kod, którego nie należy używać w produkcji bez znaczącej poprawy. Ale powinien służyć swojemu celowi w przedstawieniu ogólnego pomysłu.

Leigh Bicknell
źródło
-1

Zakładając, że szukasz w SQL i przy pełnej wartości, a nie częściowej (np. LIKE „wartość%”) ... podczas przechwytywania danych wyszukiwania, zaszyfruj te dane przy użyciu tego samego algorytmu, który był używany, gdy dane zostały zaszyfrowane i poszukaj tego.

Na przykład:

Co by było:

SELECT FieldA, FieldB 
FROM Table1 
WHERE FieldC = 'Value'

Zamiast tego może wyglądać następująco:

SELECT FieldA, FieldB 
FROM Table1 
WHERE FieldC = 'hsk&%67ghhks83'
WellyBoot
źródło
1
Nie. Przyzwoite szyfrowanie będzie działać z wartością soli, więc jeśli na przykład masz unikalną sól dla każdego wiersza, to w wierszach wyszukiwania trzeba będzie użyć soli w wierszu, stanie się to skomplikowane i drogie, dość szybko
Martin