Jak mogę chronić nazwę Użytkownika i hasło MySQL przed dekompilacją?

Pliki Java .class można dość łatwo dekompilować. Jak mogę chronić swoją bazę danych, jeśli muszę użyć danych logowania w kodzie?

Author: Keith Pinson, 2009-01-14

6 answers

Nigdy nie wprowadzaj haseł do kodu. To zostało poruszone niedawno w Top 25 najbardziej niebezpiecznych błędów programistycznych :

Hard-kodowanie tajnego konta i hasło do oprogramowania jest niezwykle wygodne - dla wykwalifikowanych inżynierowie wsteczni. Jeśli hasło jest to samo w całym oprogramowaniu, wtedy każdy klient staje się wrażliwy kiedy to hasło nieuchronnie staje się znane. I dlatego, że jest mocno zakodowany, to ogromny ból do napraw.

Informacje o konfiguracji, w tym hasła, należy przechowywać w osobnym pliku, który aplikacja odczytuje podczas uruchamiania. Jest to jedyny prawdziwy sposób, aby zapobiec wyciekowi hasła w wyniku dekompilacji (nigdy nie Kompiluj go do pliku binarnego).

Aby uzyskać więcej informacji na temat tego częstego błędu, możesz przeczytać CWE-259 Artykuł . Artykuł zawiera dokładniejszą definicję, przykłady i wiele innych informacji na temat problem.

W Javie jednym z najprostszych sposobów na to jest użycie klasy Preferences. Jest przeznaczony do przechowywania wszelkiego rodzaju ustawień programu, z których niektóre mogą zawierać nazwę użytkownika i hasło.

import java.util.prefs.Preferences;

public class DemoApplication {
  Preferences preferences = 
      Preferences.userNodeForPackage(DemoApplication.class);

  public void setCredentials(String username, String password) {
    preferences.put("db_username", username);
    preferences.put("db_password", password);
  }

  public String getUsername() {
    return preferences.get("db_username", null);
  }

  public String getPassword() {
    return preferences.get("db_password", null);
  }

  // your code here
}

W powyższym kodzie można wywołać metodę setCredentials Po wyświetleniu okna dialogowego z zapytaniem o nazwę użytkownika i hasło. Kiedy musisz połączyć się z bazą danych, możesz po prostu użyć metod getUsername i getPassword, Aby pobrać zapisane wartości. Dane logowania nie będą zakodowane na twardo w Twoich binariach, więc dekompilacja nie będzie stanowić zagrożenia bezpieczeństwa.

Ważna uwaga: pliki preferencji są zwykłymi plikami tekstowymi XML. Upewnij się, że podejmiesz odpowiednie kroki, aby uniemożliwić nieautoryzowanym użytkownikom przeglądanie plików raw(uprawnienia UNIX, uprawnienia Windows itp.). W Linuksie przynajmniej nie jest to problemem, ponieważ wywołanie Preferences.userNodeForPackage spowoduje utworzenie pliku XML w katalogu domowym bieżącego użytkownika, który i tak nie jest czytelny dla innych użytkowników. W Windows, sytuacja może być inna.

Ważniejsze uwagi: w komentarzach tej odpowiedzi i innych było wiele dyskusji na temat właściwej architektury dla tej sytuacji. Oryginalne pytanie tak naprawdę nie wspomina o kontekście, w którym aplikacja jest używana, więc będę mówić o dwóch sytuacjach, które mogę myśleć. Pierwszy to przypadek, w którym osoba korzystająca z programu zna już (i jest uprawniona do znajomości) bazę danych poświadczenia. Drugi to przypadek, w którym ty, deweloper, próbujesz utrzymać dane uwierzytelniające bazy danych w tajemnicy przed osobą używającą programu.

Pierwszy przypadek: użytkownik jest upoważniony do znajomości danych logowania do bazy danych

W tym przypadku rozwiązanie, o którym wspomniałem powyżej, zadziała. Klasa Java Preference będzie przechowywać nazwę użytkownika i hasło w postaci zwykłego tekstu, ale plik preferencji będzie czytelny tylko dla uprawnionego użytkownika. Użytkownik może po prostu otworzyć preferencje Plik XML i odczytać poświadczenia logowania, ale nie jest to zagrożenie bezpieczeństwa, ponieważ użytkownik znał poświadczenia na początku.

Drugi przypadek: próba ukrycia danych logowania przed użytkownikiem

Jest to bardziej skomplikowany przypadek: użytkownik nie powinien znać danych logowania, ale nadal potrzebuje dostępu do bazy danych. W takim przypadku użytkownik uruchamiający aplikację ma bezpośredni dostęp do bazy danych, co oznacza, że program musi znać dane logowania przed czas. Rozwiązanie, o którym wspomniałem powyżej, nie jest odpowiednie dla tego przypadku. Możesz zapisać dane logowania do bazy danych w pliku preferencji, ale użytkownik będzie mógł odczytać ten plik, ponieważ będzie właścicielem. W rzeczywistości, naprawdę nie ma dobrego sposobu, aby użyć tej sprawy w bezpieczny sposób.

Poprawny przypadek: użycie architektury wielowarstwowej

Poprawnym sposobem jest posiadanie środkowej warstwy pomiędzy serwerem bazy danych a aplikacją kliencką, która uwierzytelnia indywidualnych użytkowników i pozwala na wykonanie ograniczonego zestawu operacji. Każdy użytkownik miałby własne dane logowania, ale nie dla serwera bazy danych. Poświadczenia umożliwiłyby dostęp do warstwy środkowej (warstwy logiki biznesowej) i byłyby różne dla każdego użytkownika.

Każdy użytkownik miałby własną nazwę użytkownika i hasło, które mogłyby być przechowywane lokalnie w pliku preferencji bez żadnego zagrożenia bezpieczeństwa. To się nazywa trójwarstwowa Architektura (poziomy są twoim serwer bazy danych, serwer logiki biznesowej i aplikacja kliencka). Jest to bardziej złożone, ale tak naprawdę jest to najbezpieczniejszy sposób na tego typu rzeczy.

Podstawowa kolejność operacji to:

  1. Klient uwierzytelnia się za pomocą warstwy logiki biznesowej przy użyciu osobistej nazwy użytkownika/hasła. Nazwa użytkownika i hasło są znane użytkownikowi i nie są w żaden sposób powiązane z danymi logowania do bazy danych.
  2. jeśli uwierzytelnienie się powiedzie, klient wysyła żądanie do warstwa logiki biznesowej Prośba o informacje z bazy danych. Na przykład spis produktów. Zwróć uwagę, że żądanie klienta nie jest zapytaniem SQL; jest to zdalne wywołanie procedury, takie jak getInventoryList.
  3. Warstwa logiki biznesowej łączy się z bazą danych i pobiera żądane informacje. Warstwa logiki biznesowej odpowiada za tworzenie bezpiecznego zapytania SQL na podstawie żądania użytkownika. Wszelkie parametry zapytania SQL powinny być dezynfekowane, aby zapobiec SQL injection ataki.
  4. warstwa logiki biznesowej wysyła listę zapasów z powrotem do aplikacji klienckiej.
  5. klient wyświetla listę zapasów użytkownikowi.

Zauważ, że w całym procesie, Aplikacja kliencka nigdy nie łączy się bezpośrednio z bazą danych. Warstwa logiki biznesowej otrzymuje żądanie od uwierzytelnionego użytkownika, przetwarza żądanie Klienta o listę zapasów, a dopiero potem wykonuje zapytanie SQL.

 109
Author: William Brendel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-18 08:02:21

Umieść hasło w pliku, który aplikacja odczyta. Nigdy nie osadzaj haseł w pliku źródłowym. Kropka.

Ruby ma mało znany moduł o nazwie dbi::DBRC do takiego użycia. Nie mam wątpliwości, że Java ma odpowiedniki. W każdym razie, nie jest trudno napisać jeden.

 15
Author: Keltia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-08 07:22:45

Piszesz aplikację internetową? Jeśli Tak, użyj JNDI, aby skonfigurować go zewnętrznie do aplikacji. Przegląd jest dostępny tutaj :

JNDI zapewnia jednolity sposób na aplikacja do wyszukiwania i dostępu zdalnego usługi przez sieć. The remote usługa może być dowolną usługą przedsiębiorstwa, w tym Komunikator lub usługa specyficzna dla aplikacji, ale z Oczywiście, aplikacja JDBC jest zainteresowany głównie bazą danych obsługa. Once a DataSource obiekt jest utworzone i zarejestrowane w JNDI naming service, aplikacja może używać API JNDI, aby uzyskać dostęp do tego źródła danych obiekt, który następnie można wykorzystać do połącz się ze źródłem danych reprezentuje.

 3
Author: Tim Howland,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-14 13:28:15

Bez względu na to, co zrobisz, poufne informacje będą przechowywane w jakimś pliku gdzieś. Twoim celem jest, aby to jak trudne do uzyskania, jak to możliwe. To, jak wiele z tego możesz osiągnąć, zależy od projektu, potrzeb i grubości portfela Twojej firmy.

Najlepszym sposobem jest nie przechowywać żadnych haseł w dowolnym miejscu. Można to osiągnąć za pomocą funkcji hash do generowania i przechowywania hashów haseł:

hash("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
hash("hbllo") = 58756879c05c68dfac9866712fad6a93f8146f337a69afe7dd238f3364946366
Algorytmy haszujące są funkcjami jednokierunkowymi. Zamieniają dowolną ilość danych w "odcisk palca" o stałej długości, którego nie można odwrócić. Oni także mieć właściwość, że jeśli Dane wejściowe zmienią się nawet odrobinę, to wynikowy hash jest zupełnie inny (patrz przykład powyżej). To jest świetny do ochrony haseł, ponieważ chcemy przechowywać hasła w formie, która je chroni, nawet jeśli sam plik hasła jest skompromitowane, ale jednocześnie musimy być w stanie zweryfikować, że hasło użytkownika jest poprawne.

niepowiązane Uwaga: w dawnych czasach internetu, po kliknięciu łącza "Zapomniałem hasła", strony internetowe wysyłają ci swoje hasło tekstowe. Pewnie przechowywali je gdzieś w bazie danych. Kiedy hakerzy uzyskali dostęp do swojej bazy danych, uzyskali dostęp do wszystkich haseł. Ponieważ wielu użytkowników używało tego samego hasła w wielu witrynach internetowych, był to ogromny problem z bezpieczeństwem. Na szczęście w dzisiejszych czasach nie jest to powszechna praktyka.

Teraz pojawia się pytanie: co jest najlepsze sposób przechowywania haseł? Ja bym uznał to rozwiązanie (uwierzytelnianie i zarządzanie użytkownikami usługi stormpath ' S) za cholernie idealne:

  1. Twój użytkownik wprowadza poświadczenia, a to jest potwierdzone przed hash hasła
  2. hasła są generowane i przechowywane, a nie hasła
  3. Hasze są wykonywane wiele razy
  4. Hasze są generowane przy użyciu losowo wygenerowanej soli
  5. Hasze są szyfrowane za pomocą prywatnego klucz
  6. Klucz prywatny jest przechowywany w fizycznie innym miejscu niż hash.]}
  7. klucze prywatne są aktualizowane w oparciu o CZAS
  8. zaszyfrowane skróty dzielą się na kawałki
  9. te kawałki są przechowywane w fizycznie oddzielnych miejscach
Oczywiście nie jesteś ani google, ani bankiem, więc jest to dla Ciebie przesadne rozwiązanie. Ale potem pojawia się pytanie: ile bezpieczeństwa wymaga Twój projekt, ile masz czasu i pieniędzy?

Dla wielu aplikacje, choć nie zalecane, przechowywanie hasła w kodzie może być dobrym rozwiązaniem. Jednak poprzez łatwe dodanie kilku dodatkowych kroków zabezpieczeń z powyższej listy, możesz znacznie zwiększyć bezpieczeństwo swojej aplikacji.

Załóżmy na przykład, że Krok 1 nie jest akceptowalnym rozwiązaniem dla Twojego projektu. Nie chcesz, aby użytkownicy wprowadzali hasło za każdym razem lub nawet nie chcesz/nie potrzebujesz, aby użytkownicy znali hasło. Nadal masz gdzieś poufne informacje i chcę to chronić. Masz prostą aplikację, nie ma serwera do przechowywania plików lub jest to zbyt wiele kłopotów dla Twojego projektu. Aplikacja działa w środowiskach, w których bezpieczne przechowywanie plików nie jest możliwe. Jest to jeden z najgorszych przypadków, ale nadal z niektórych dodatkowych środków bezpieczeństwa można mieć znacznie bezpieczniejsze rozwiązanie. Na przykład możesz przechowywać poufne informacje w pliku i zaszyfrować plik. Możesz mieć szyfrowany klucz prywatny na twardo zakodowany w kod. Możesz zaciemnić kod, więc utrudniasz komuś jego złamanie. Istnieje wiele bibliotek do tego celu, zobacz ten link . (Ostrzegam jeszcze raz, że nie jest to w 100% bezpieczne. Inteligentny haker z odpowiednią wiedzą i narzędziami może to zhakować. Ale w oparciu o twoje wymagania i potrzeby, może to być wystarczająco dobre rozwiązanie dla Ciebie).

 2
Author: Caner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-19 11:48:02

To pytanie pokazuje, jak przechowywać hasła i inne dane w zaszyfrowanym pliku: Java 256-bitowe szyfrowanie oparte na hasłach AES

 1
Author: Aaron Digulla,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:03:04

MD5 jest algorytmem hash, a nie algorytmem szyfrowania, w skrócie u cant get back wat u hashed, u can only compare. Powinien być najlepiej używany podczas przechowywania informacji uwierzytelniających użytkownika, a nie db nazwa użytkownika i hasło. db username i pwd powinny być zaszyfrowane i przechowywane w pliku konfiguracyjnym, co najmniej.

 0
Author: renegadeMind,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-14 13:55:50