MySQL - kto jest zalogowany

0

Witam
Zaczynam zabawę z dostępem do bazy poprzez Internet.
Żeby było bezpiecznie, chcę całą logikę przetwarzania umieścić po stronie serwera, a poleceniami GRANT daję zezwolenia na uruchamianie odpowiednich procedur dla grup użytkowników. I tu się pojawia pewna moja wątpliwość. Podczas logowania, silnik sprawdza, czy zgłoszony user/hasło ma dostęp do bazy i zgodnie z przydzielonymi wcześniej dostępami, pozwoli mu na uruchamianie pewnych procedur, ale bez fizycznego dostępu do danych (czyli SELECT nie, EXECUTE tak). Jako hasło mogę do bazy wpisywać jednostronnie szyfrowanie np. poprzez MD5(), czyli aplikacja Delphi klienta, przed wysyłką hasła też je zaszyfruje. Wywołania parametrów tekstowych sprawdzę pod kątem Code Injection. Do tej pory wszystko wydaje się zrozumiałe.
Moje wątpliwości dotyczą samego wywoływania procedur, np. dopisywania informacji o graczu. Jeżeli Kowalski i Wiśniewski mają te same uprawnienia, to po zalogowaniu do bazy, wywołania:
CALL grupa.edytuj_gracza("Kowalski",nowa_wartość)
jak i:
CALL grupa.edytuj_gracza("Wiśniewski",nowa_wartość)

będą w pełni legalne. Jeżeli dostęp następuje z mojej aplikacji, to ona wstawi prawidłowy nick lub ID. Jeżeli jednak ktoś połączy się zewnętrzną konsolą, to po zalogowaniu jako Kowalski, bez problemu może wywołać procedurę jako "Wisniewski", bo ma do tego prawo. Jak się przed tym zabezpieczyć?

  1. Czy istnieje jakaś zmienna, która zwiera informację, kto jest zalogowany - wtedy wywołam tylko:
    CALL grupa.edytuj_gracza(nowa_wartość)
    a procedura wstawi sobie jakiś Current_user_ID?

  2. czy można deklarować zmienne, które będą widoczne dla wszystkich wbudowanych procedur - wtedy podczas logowania umieszczę tam właściwy ID użytkownika.

Z góry dziękuję za wskazówki. W googlach zadaję niewłaściwe pytania, bo dostaję milion niewłaściwych odpowiedzi ;)

0

Nie polecam raczej wywoływania procedur bezpośrednio z aplikacji klienckich, tworzenie systemu autentykacji i autoryzacji w SQL to dla mnie dość dziwny pomysł i IMO T-SQL jest na to zbyt ograniczony. Być może stworzenie na serwerze dodatkowego webservice, który będzie stanowił furtkę to dodatkowa praca, ale to dość dobre rozwiązanie.

0

Czy MySQL nie posiada wbudowanych mechanizmów? Przecież dołożenie czegokolwiek z zewnątrz nie poprawi bezpieczeństwa silnika bazy, do którego można się dostać inaczej. To tak, jakby ktoś wstawił pancerną furtkę do ogrodu otoczonego niskim drewnianym płotkiem ;)

0

W bazie danych wyłączasz zewnętrzny dostęp, usuwasz użytkowników. Na tym samym serwerze (albo w sieci lokalnej czy jak tam chcesz) tworzysz webservice, usługę pośredniczącą, która będzie obsługiwała autentykację i autoryzację. Tylko ta usługa będzie miała dostęp do bazy danych, to ona będzie filtrować wyniki, a z resztą jak już sam zauważyłeś, połączyć logowanie konkretnego użytkownika z przekazywaniem do bazy danych jego nazwy.

0

Dzięki za wskazówkę. Rozwiązanie być może najlepsze, jednak to oznaczało by konieczność opanowania następnej technologii, na co w tej chwili nie mam czasu. Gdyby więc ktoś odpowiedział na zadane pytania, być może uda się rozwiązać problem prostszymi środkami :)
PS. Hosting będzie zewnętrzny

0

Na razie wymyśliłem:
Rozwiązanie 1: SESSION_USER() zwraca np. root@localhost
Rozwiązanie 2: CALL grupa.edytuj_gracza("Wiśniewski", hasło, nowa_wartość)
czyli autentykacja następuje przy każdym wywołaniu procedury - w sumie troszkę wolniej, co nie ma specjalnego znaczenia przy tej skali, jednak hasło lata bez przerwy po necie

1

Podpinanie się klientem z zewnątrz bezpośrednio do bazy to zły pomysł. Poza tym, że hasło będzie latać po sieci, to dodatkowo będą latać zapytania - na tej podstawie praktycznie laik wyczyści Ci bazę, czy doda jakieś bzdury.
Hasło jako takie w ogóle nie powinno być przesyłane przez sieć: do tego stosuje się algorytmy haszowania np. SHA256 i najlepiej jeszcze z solą(MD5 o którym wspomniałeś jest zdecydowanie zbyt słabe).

Napisanie czegoś pośredniczącego nie jest trudne (wystarczy choćby znajomość socket'ów - a je można ogarnąć w chwilę). Np. wysyłasz pakiet z klienta z identyfikatorem zapytania, jakimś wygenerowanym nr sesji i parametrami tego zapytania.

0

O generowaniu klucza sesji nawet myślałem, ale zaraz pojawiły się problemy, co w przypadku zalogowania usera z dwóch kompów jednocześnie, utraty neta, zostawienia włączonego programu na noc, daty ważności klucza itp, więc uznałem to za zbyt niedoskonałe.
Zapytania latać zbytnio nie będą, ponieważ user ma prawo wyłącznie wywołać procedury (ścisły katalog), który wykona zestaw dopuszczalnych czynności - robię kontrolę poprawności danych, filtrowanie niebezpiecznych wyrażeń itp. Technika, o której wpominasz, gdzieś mi wpadła w oko - muszę odnaleźć artykuł, ale praktycznie chciałem zrobić coś analogicznego. Dzięki za wskazanie silniejszego zabezpieczenia. SHA w MySQL widzę, że jest, SHA256 muszę poszukać.

Edit: W MySQL jest wbudowana funkcja SHA2(string, długość klucza=224, 256, 384, 512) więc implementacja jest bardzo łatwa. Czy są gotowe biblioteki do Delphi?

1

Na pewno są gotowe biblioteki (ot jeden z pierwszych wyników google http://www.cityinthesky.co.uk/opensource/DCPcrypt), choćby dlatego, że takich algorytmów w poważnych przedsięwzięciach nie implementuje się samemu (jest jakaś instytucja, która certyfikuje implementacje tego typu rzeczy).

Co do problemów z id sesji, o których wspomniałeś to decyzje podejmie aplikacja działająca jako serwer. Możesz np. po zalogowaniu się tego samego usera z innego kompa odciąć tego wcześniejszego(usunąć id sesji z puli, zamknąć połączenie), podobnie z czasem obowiązywania itd. Wbrew pozorom jest to dość proste do zaprojektowania i zaimplementowania.
W miarę nie dawno coś takiego pisałem, tyle że w Javie i zajęło to może z 50 linii kodu(jak nie mniej).

0

Bardzo dziękuję :) Pocieszające jest to, że z konsoli wygenerowanie SHA512 ma czas <0.05 (przeważnie 0.0), więc można pójść na maxa :) Mam nadzieję, że Delphi będzie równie wydajne :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1