MySql jak nadać uprawnienia na rekordy?

Witam,

posiadam utworzoną bazę danych : załóżmy że są tam tabele Pracownik(idpracownik, imie, nazwisko), oraz Zlecenie(idzlecenie, idpracownik, opis). Stworzyłem program, z którego będzie korzystało wiele osób - umożliwia on dodawanie rekordów do tabel, edytowanie i usuwanie. Zawiera on moduł logowania, w którym wpisuje się identyfikator pracownika - na jego podstawie pobierane są rekordy z bazy danych - w ten sposób użytkownik pracuje wyłącznie na rekordach dla niego przeznaczonych.

Problemem jest zabezpieczenie bazy danych - do połączenia z bazą danych wykorzystywane jest konto “roota”. Zastanawiam się nad stworzeniem użytkownika z uprawnieniami select, insert, update, oraz delete dla wybranej bazy danych - będzie to o wiele bezpieczniejsze :slight_smile: Rodzi się kolejny problem - ponieważ w ten sposób, ktoś kto chciałby namieszać w bazie danych, mógłby nie korzystać ze stworzonego przeze mnie programu, ale bezpośrednio zalogować się do PhpMyAdmin. W ten sposób zobaczy on nie tylko swoje rekordy, ale wszystkie rekordy z tabel do których ma uprawnienia.

Jak w takim razie nadać uprawnienia użytkownikowi np. “user”, aby miał dostęp do tabeli Pracownicy ale tylko rekordu, którego id = 1, oraz tabeli Zlecenia ale tylko rekordów gdzie idpracownik = 1. Tabele są ze sobą powiązane tzn. pracownik może mieć wiele zleceń, ale zlecenie należy do 1 pracownika (stąd klucz obcy idpracownik w tabeli Zlecenia).

Chodzi mi o to, że nawet jak ten user zaloguje się do phpmyadmin to będzie mógł robić tylko to samo co w moim programie - czyli przeglądać tabele z rekordami, których id = 1.

Zasadniczo nie wykonalne.

Ew. mógłbyś rekordy dotyczące konkretnego użytkownika szyfrować XOR-em, jednak będzie to powodowało zwiększenie konsumpcji zasobów, a podniesie bezpieczeństwo zależnie od skomplikowania danych jakie użyjesz jako klucz.

Technik utrudniających penetrację jest dużo, ale 100% pewnej brak. Widziałem już wiele skomplikowanych mechanizmów pośredniczących między serwerem a programem, który jest używany przez użytkowników końcowych - w razie naruszenia bezpieczeństwa programu frontend-owego zły użytkownik musi pokonać program pośredniczący przed dostaniem się do bazy danych.

Pamiętaj jednak, że cały program jest tak bezpieczny jak jego najsłabszy punkt.

Trochę nie chce mi się wierzyć, aby było to niewykonalne :wink: Może jeszcze raz napiszę o co mi chodzi …

W bazie danych posiadam tabelę “Zlecenia” z kolumnami “idzlecenie, idpracownik, opis”. Tabela Zlecenie zawiera 5 rekordów :

id_zlecenie, id_pracownik, opis

1 1 aaaa

2 1 vvvv

3 2 dddd

4 3 ssss

5 1 cccc

W programie mam ustawione, że logując się na użytkownika o identyfikatorze 1 z bazy danych są pobierane rekordy z tabeli “Zlecenia” gdzie id_pracownik = 1 (to jest łatwe do zrobienia). Jednak do połączenia z bazą danych wykorzystywane jest konto z uprawnieniami, które pozwala przeglądać wszystkie rekordy w tabelach - czyli ktoś logując się na PhpMyAdmin zobaczy rekordy należące do pracownika z id =2, oraz z id=3 i może coś pomieszać. Czy można to jakoś zabezpieczyć ?

Specem od MySQL nie jestem więc dlatego napisałem zasadniczo, wedle mojej skromnej wiedzy można nadawać uprawnienia dla użytkowników na bazy i tabele.

Przy tej architekturze bazy danych ciężko (wedle mojej wiedzy) musiałbyś mieć tabele oddzielne dla każdego użytkownika i dla każdego z nich dodać jako użytkownika MySQL.

Dlatego proponowałbym stworzyć program pośredniczący między użytkownikiem i bazą danych - wtedy ograniczyć ruch z bazy danych do programu pośredniczącego, a go samego traktować jako źródło danych i można się wtedy bawić w szyfrowanie transmisji i temu podobne bajery - jednak bezpieczeństwo całego systemu będzie zależeć wtedy od pośrednika i zabezpieczeń serwera.

Tylko, że ja nie mogę ograniczyć się do jednego programu pośredniczącego, ponieważ będzie on wykorzystywany przez wielu pracowników jednocześnie. W takim razie może ktoś inny ma jakiś pomysł jak rozwiązać mój problem ?

A czemu program pośredniczący miałby się ograniczać się do obsługi jednego użytkownika?

Ba, żeby uprościć sobie życie możesz zastosować technikę wielowątkową co da Ci lepszą responsywność i bardziej zbalansowane zużycie zasobów.

Inaczej - programy mam już zaimplementowane i działają. Pracownik 1 pobiera program wpisuje dane do połączenia z bazą danych i gotowe, to samo robi Pracownik 2. Teraz chciałbym stworzyć w bazie danych użytkownika z uprawnieniami opisanymi powyżej - tak aby Pracownik 1 i Pracownik 2 nie mogli namieszać sobie gdyby chcieli ręcznie wejść do PhpmyAdmin.

Ja w Twoim wypadku nie dał bym dostępu do phpMyAdmin i bym ograniczył ich co do najwyżej skryptu z własnym logowaniem i dodatkowo relacje między tabelami i to wg mnie by było łatwiejsze do opanowania.

Chodzi mi dokładniej:

Pracownik o id 1 odczytuje tylko i wyłącznie dane z tabeli Zamówienia o id_pracownik = 1.

Jeśli by coś nawaliło, to można via WWW utworzyć skrypt, który pozwoli po zalogowaniu pracownika, na edycję jego zamówień (czyli id_pracownik = 1) nie kolidującą z innym pracownikiem dajmy na to id 3, bo u niego będą wyświetlane tylko zamówienie o id_pracownik = 3. Bezpieczniejsza jest tam metoda, niż dawanie dostępu to phpMyAdmin.

Ja też nie chcę dać dostępu do phpmyadmin - tylko jak to zrobić. Już pisałem, że program musi się łączyć z bazą danych aby pobrać tabele - zatem w programie są informacje : nazwa serwera, login, hasło, baza danych. Skoro te informacje są zapisane w programie to użytkownik może się nimi posłużyć do zalogowania do phpmyadmin.

Nie można na przykład, każdemu użytkownikowi stworzyć perspektywy? Jako źródło danych dla perspektywy JanKowalski podajesz tabele z której wybierasz te rekordy, które są Jana Kowalskiego (będzie to wymagać jakiegoś dyskryminatora).

Jeśli ludzie którzy będą z tego korzystać to np. jedna firma, nie ma wysokiego priorytetu na zabezpieczenie tych danych a jedynie chciałbyś uniemożliwić szperanie ciekawskim to po prostu szyfrujesz dane połączenia do bazy dany i odszyfrowujesz je w kodzie. Ktoś musiałby analizować pakiety wychodzące żeby znaleźć odszyfrowane hasło, a jeśli użyjesz szyfrowanego połączenia do DB to zwykłych użytkowników masz z głowy. Jeśli chcesz to zrobić bezpiecznie i profesjonalnie to nie dajesz użytkownikowi dostępu do bazy danych w ogóle. Stawiasz serwer pośredniczący pomiędzy użytkownikiem a bazą danych. Uruchamiasz na serwerze webservice z api niezbędnym do realizacji zadania. Czyli przykładowo webservice udostępnia metodę na zewnątrz loadPracownik(pracownikId), a z poziomu kodu serwera ładujesz i zwracasz tylko te rekordy do których jest uprawniony dany użyszkodnik.

Dlatego dane do zalogowania powinny być już wpisane np w program. Jeśli obsługa miała by się odbywać via WWW to pliki nie będą przecież dostępne dla ogółu. Stwórz tabele z pracownikami zawierającą loginy i hasła dodatkowo, później skrypt logowania i po zalogowaniu odczytać id pracownika i zachować do wglądu reszcie skryptów, tak by były widoczne tylko zlecenia dla danego pracownika.

Czyli plików parę by było, odnośnie konfiguracji i innych funkcji, jak i plików do obsługi pracowników. Akurat robiłem kiedyś coś takiego, ale trochę bardziej było to rozbudowane i było łatwiejsze niżeli pisanie programów od początku. Tak to się włącza przeglądarkę i się działa, dane można edytować z każdego miejsca i w obojętnie jakim czasie, a każdy pracownik dostaje swój unikalny login i hasło.

Dodane 14.06.2012 (Cz) 1:53

Potwierdzam to co napisał kolega, dzisiaj do małej firmy starczy nawet terminal z serwerem i dyskiem. Rozwiązanie tanie i dobre, sam posiadam w domu terminal i to nie za dobry (800 MHz i 512 Mb RAM i dysk), ale podczas obciążenia które testowałem wydala na ok 25 osób, które wysyłają ciągłe żądania. Jeśli lepiej skonfigurować to by napewno więcej wydolił, ale to na parę osób się nie opłaca mi tego robić.

Tak byłoby najlepiej - ale jak wcześniej pisałem na wstępie nie wiem z jakiej bazy (jaka nazwa i jaki serwer) będzie korzystał program. Dodatkowo wykorzystuje dwa programy - jeden dla administratora (tam nie mam potrzeby ukrywania danych do bazy dany) i jeden dla pracownika (tutaj nie chciałbym aby on mógł szperać w bazie danych przez phpmyadmin).

W ten sposób mam to zrealizowane w programie pracownika - logując się podaje on identyfikator i hasło. Na podstawie identyfikatora podsuwam mu zlecenia wyłącznie dla niego. Jednak przy logowaniu podaje on informacje potrzebne do połączenia z bazą danych np. serwer, nazwa bazy danych, login i hasło.

Reasumując, wpadłem na pewne rozwiązania - jednak nie jestem co do nich przekonany :slight_smile:

  1. Program administratora, podczas tworzenia nowej bazy danych stworzy konto użytkownika (jedno dla wszystkich pracowników) z uprawnieniami (SELECT) dla tabeli Ustawienia. Tabele Ustawienia będzie przechowywała login i zaszyfrowane hasło, dla konta z uprawnieniami (SELECT, UPDATE) dla pozostałych tabel.

W programie pracownika będzie zaimplementowany login i hasło dla konta z uprawnieniami do przeglądania tabeli SELECT. W ten sposób pracownik podczas logowania będzie podawał jedynie nazwę bazy danych i nazwę serwera (oprócz tego swój identyfikator i hasło). Program pracownika połączy się z tabelą Ustawienia i pobierze login i zaszyfrowane hasło - które rozszyfruje za pomocą zaimplementowanego klucza. Od teraz podczas łączenia się z bazą danych program pracownika będzie korzystał z konta mającego uprawnienia do pozostałych tabel. W ten sposób wyeliminuje konieczność podawania pracownikowi loginu i hasła do bazy danych…

Co o tym myślicie ?

  1. Drugi pomysł - łatwiejszy w realizacji. Po prostu, podczas tworzenia bazy danych za pomocą programu administratora stworzyć konto z uprawnieniami do przeglądania odpowiednich tabel. Login i hasło byłoby zawsze takie samo. W programie pracownika zaimplementować ten login i hasło, tak żeby nie widział go pracownik. Pracownik wpisywałby podczas logowania tylko serwer i nazwę bazy danych (oprócz tego swój identyfikator i hasło). Dzięki temu nie będzie znał hasła do bazy danych i nie wejdzie do phpmyadmin. Jest to jakieś zabezpieczenie, ale w momencie gdy administrator wejdzie do phpmyadmin i ręcznie odczyta np. login i hasło konta pracownika i poda je np. w internecie (taki psikus). To przyszłe osoby, które będą korzystały z programu będą mogły wykorzystać te informacje - tak jak pisałem konto z odpowiednimi uprawnieniami miałoby zawsze ten sam login i hasło i w programie pracownika nie można by tego zmienić (byłoby wpisane na stałe). Gdybym chciał umożliwić wpisanie loginu i hasła ręcznie to znowu musiałbym przekazywać je pracownikowi i wracamy do początku :slight_smile:

Ale ja dalej nie rozumiem po co podawanie nazwy serwera i nazwa bazy ma być podawana. Do mnie właśnie to nie dociera za bardzo. No jak będzie serwer to wtedy te dane się uzupełni przecież.

Do drugiego sposobu to ja nie mówię że ma mieć dostęp do phpMyAdmin, tylko ma mieć dostęp do wyciągnięcia tych danych i co najwyżej edycji tych danych, nic ponadto. Na DP też masz konto i nie wiesz jakie jest hasło do bazy itd i w tym wypadku tutaj możesz edytować swoje dane itp, ale nie od kogoś innego i o to samo mi biega. Gdyby baza SQL zmieniła adres to po prostu admin zmienia dane i już wszystko działa jak należy.

@desperado:

Kombinujesz zbędnie, jeśli podajesz każdemu użytkownikowi login i hasło do bazy danych to w jaki sposób chcesz mu potem zabronić modyfikacji rekordów które da się przy pomocy tych danych autoryzacyjnych zmodyfikować?

Skopałeś na etapie projektowania i w tym momencie wdrożenie lepszego zabezpieczenia będzie pracochłonne więc i kosztowne.

Mogłeś zastosować architekturę klient<->serwer, gdzie klient służyłby tylko za front-end. Wtedy wszystkie operacje wykonuje serwer (takie jak pobranie odpowiednich rekordów z bazy, autoryzacja użytkownika, itp).

W większości aplikacji gdzie istnieje konieczność współpracy grupy ludzi stosuje się takie rozwiązanie - jest ono po prostu ekonomiczne zarówno we wdrożeniu jak i obsłudze.

Czy to znaczy, że masz dziesięć serwerów, na każdym pięć baz, i codziennie pracownik wybiera sobie inną bazę do pracy? Jeśli tak, to moim zdaniem jest to bardzo dziwne.

Nawet jeśli, to i tak:

  1. Baza ma użytkownika z prawami tylko odczytu i zapisu rekordów (bez praw tworzenia/usuwania tabel, itd.) z jakimś tam loginem i hasłem.

  2. Program łączy się bazą na koncie tego użytkownika, login i hasło jest albo wkompilowane w kodzie programu albo zaszyfrowane w pliku konfiguracyjnym i odszyfrowywane przez program przed połączeniem.

  3. Jeśli baz jest więcej niż jedna, to po prostu każda ma swojego użytkownika z loginem i hasłem, które tak jak w punkcie wyżej są albo na stałe w programie albo zaszyfrowane w pliku. Użytkownik programu nadal może wybrać serwer i bazę, ale nie zna loginu i hasła do bazy.

  4. Pracownik - użytkownik programu (to nie to samo, co użytkownik bazy), loguje się do programu, podaje swój login i hasło, które to dane są porównywane z loginem i hashem hasła przechowywanym w jednej z tabel w bazie. Oczywiście, jeśli baz jest wiele, to każdy użytkownik programu musi mieć w każdej z nich to samo hasło.

To wtedy zostanie dyscyplinarnie zwolniony z pracy, a poza tym grozi mu grzywna, jeżeli nie więzienie.

Z tego co czytam system jest jeszcze w początkowej fazie realizacji, więc radzę Ci już teraz postawić serwer pośredniczący, przynajmniej dla operacji z DB. Postawić np. tomcata który zajmie się autoryzacją i udostępni potrzebne interfejsy wcale długo Ci nie zajmie. Kod odpowiadający za selekcje danych z bazy i tak gdzieś będziesz musiał napisać. Jeśli chcesz aby dane w bazie były zabezpieczone to na pewno nie powinieneś dawać bezpośredniego dostępu do bazy klientowi. Taka architektura zapewni Ci też większą modularność na przyszłość, co sprawi że system będzie łatwiej utrzymać i rozwijać. Przy obecnej architekturze nawet jeśli zaszyfrujesz hasła musisz być świadom tego że dane będą słabo strzeżone i liczysz wtedy głównie na to że użytkownicy systemu nie będą w niego nielegalnie ingerować.