Ukrycie / usunięcie connection string z pamięci

1

Cześć,

Piszę prostą aplikację bazodanową i staram się ją zabezpieczyć na tyle, żeby nie dało się pozyskać hasła do bazy danych z pamięci. Connection Stringa nie przechowuję w żadnych plikach, ale każdą poszczególną informację osobno w rejestrach Windows. Hasło oczywiście zaszyfrowane. Nie chcę wchodzić w dyskusję na temat tego, że i tak nie jest to w 100% bezpieczne rozwiązanie, bo tak naprawdę żadne przechowywanie haseł nie jest.

Moim problemem jest to, że dzięki programowi ProcessHacker (taka nakładka na Task Managera) mogę dostać się do pamięci każdego wątku (w tym mojej aplikacji) i podejrzeć m.in. connection stringa. Innymi programami, specjalnie do tego przeznaczonymi byłoby to pewnie jeszcze prostsze.

Każde połączenie do bazy jest inicjowane ad hoc. Nie trzymam połączenia przez całe działanie programu. Metoda GetConnectionString() pobiera dane z rejestrów (w tym hasło) i je dekoduje oraz zwraca ciąg znaków (return $"SERVER={server}; UID={uid}; DATABASE={database}; PASSWORD={password}; PORT={port}"; ) za każdym razem.

Połączenia do bazy są otwierane z przy użyciu using () , a mimo to w pamięci wciąż widać pełny connection string ze zdekodowanym hasłem, jak widać w załączniku.

Korzystam z MySql i komponentów MySql.Data (v.8.0.20.0) z NuGeta

 using (MySqlConnection connection = new MySqlConnection(DataAccess.GetConnectionString()))
{ 
  connection.Open();
  string query = " SELECT REKORD FROM TABELA " ;                                 
  using (MySqlCommand command = new MySqlCommand(query, connection))
  {
  (pobieranie rekordów itd)
  } 
}
                	

Podpowiedzcie mi, dobrzy ludzie, jak ukryć tę informację...Przynajmniej na czas, gdy połączenie nie jest otwarte.

screenshot-20200714145445.png

1

Temat wałkowany wielokrotnie, do znudzenia.
Jeżeli trzymasz bazę danych na zewnętrznym serwerze i ta baza danych nie jest przydzielona na własność wyłącznie temu użytkownikowi u którego chcesz te dane ukryć to nie kombinujesz nic z ukrywaniem - bo to i tak można łatwo obejść - tylko łączysz się z bazą przez API.
W API definiujesz zestaw dozwolonych operacji, gradację uprawnień itd.

1

Apki C# się pięknie dekompilują, w tym algorytm odczytu w/w danych. Nie ma potrzeby wchodzić w pamięć procesu, jesteś w tym punkcie przesadnie wrażliwy (a skoro tak, pewnie dziur masz więcej gdzie indziej)

Kiedyś w zaszyfrowanym skrypcie PowerShella + DLL .NET wquwiłem się zawieszaniem i pokazałem "tfurcy" błędy projektowe i impelmentacyjne. Generalnie rozwiązanie było szyfrowane chyba ze wstydu

1

Odpowiadając na pytanie nie zważając na sens - bo przy odpowiednich ograniczeniach na systemie to może być nawet wystarczające zabezpieczenie.

Połączenia w ADO.NET są trzymane w connection pool, wywoływanie .Open i .Close (wywołane przez .Dispose w using) tak naprawdę nie zawsze otwiera i zamyka połączenia tylko wyjmuje lub zwraca je do puli - w ten sposób można mieć prostszy kod który nie będzie za każdym razem łączył się od zera do bazy. Jeśli chcesz naprawdę zamknąć połączenie to musisz je wyłączyć z puli - nie robiłem tego nigdy, ale prawdopodobnie możesz to zrobić z connection stringa przy użyciu Enlist=false, lub użyć ClearPool na połączeniu

https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql-server-connection-pooling
https://docs.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlconnection.clearpool?view=dotnet-plat-ext-3.1

To powinno zamknąć połączenie za każdym razem co wpłynie negatywnie na performance ale prawdopodobnie zmniejszy czas w którym hasło jest w jawnej postaci w pamięci. Pamiętaj żeby testować w trybie Release.

Jeśli nie chcesz żeby jakiś string był jawnie w pamięci to możesz użyć SecureString, ale w tym przypadku nie jest to szczególnie pomocne (choć możesz użyć SecureStringa zamiast swojego algorytmu szyfrowania za każdym razem).

1

Możesz zrobić tak że każdy user na swoje konto użytkownika w mysql'u i loguje się swoim hasłem (aplikacja pyta o to hasło przed uruchomieniem). Wtedy nawet jak user dostanie się do bazy to powinien mieć tak ograniczone uprawnienia że nie zrobi dropa na wszystkim.

Warto też określić przed czym chcesz się zabezpieczyć. Domyślam się że żeby podłączyć się toolem do programu trzeba mieć co najmniej konto admina (inaczej to poważne naruszenie izolacji pomiędzy programami). Jak ktoś ma admina to jakby Ci tu powiedziec nawet jak usuniesz z pamięci to jakoś to hasło wyciągnie, np:

  • Dekompilując program (.NET się super łatwo dekompiluje, ILSpy)
  • Używając WireSharka żeby podejrzeć ruch sieciowy (jak ma admina to sobie doda extra root-cert i będzie mógł podglądać ruch po HTTPS)
  • Zmodyfikuje .NET Corea tak żeby logował wszystko co się piszę na Sockety i użyje tak zmodyfikowanej wersji do uruchomienia twojego programu
    -... (za cięki jestem w hackowaniu, ale eksperci pewnie więdzą co się robi)
0

Dziękuję wszystkim za odpowiedzi.

var - tak, w przypadku, gdy chodzi o bazę na zewnętrznym serwerze to się zgadza. Ale w moim przypadku wcale tak być nie musi.

0xmarcin napisał(a):

Możesz zrobić tak że każdy user na swoje konto użytkownika w mysql'u i loguje się swoim hasłem (aplikacja pyta o to hasło przed uruchomieniem). Wtedy nawet jak user dostanie się do bazy to powinien mieć tak ograniczone uprawnienia że nie zrobi dropa na wszystkim.

Warto też określić przed czym chcesz się zabezpieczyć. Domyślam się że żeby podłączyć się toolem do programu trzeba mieć co najmniej konto admina (inaczej to poważne naruszenie izolacji pomiędzy programami). Jak ktoś ma admina to jakby Ci tu powiedziec nawet jak usuniesz z pamięci to jakoś to hasło wyciągnie, np:

  • Dekompilując program (.NET się super łatwo dekompiluje, ILSpy)
  • Używając WireSharka żeby podejrzeć ruch sieciowy (jak ma admina to sobie doda extra root-cert i będzie mógł podglądać ruch po HTTPS)
  • Zmodyfikuje .NET Corea tak żeby logował wszystko co się piszę na Sockety i użyje tak zmodyfikowanej wersji do uruchomienia twojego programu
    -... (za cięki jestem w hackowaniu, ale eksperci pewnie więdzą co się robi)

Generalnie tak jest, że każdy user ma swoje hasło. Ale nie o to w tym wszystkim chodzi. Po prostu irytuje mnie, to że hasło, coś co powinno być chronione jest wpisane plain textem. Co do dekompilacji, to już wymaga jakiejś wiedzy, a mnie chodzi o ochronę przed zwykłym, niedzielnym użytkownikiem z niekonwencjonalnymi pomysłami.

W każdym razie dzięki. Spróbuję jak to się zachowa po czyszczeniu puli połączeń.

0
danijjel napisał(a):

Co do dekompilacji, to już wymaga jakiejś wiedzy, a mnie chodzi o ochronę przed zwykłym, niedzielnym użytkownikiem z niekonwencjonalnymi pomysłami.

Nie wymaga :)

https://www.google.com/search?client=firefox-b-d&q=jak+zdekompilowa%C4%87+plik+exe

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.