Czy odbicie jest niekorzystne, ponieważ zmiennych prywatnych nie można ograniczyć?

14

privateModyfikator jest stosowany w celu ograniczenia dostępu spoza klasy, ale przy użyciu odbicia inne klasy mogą uzyskać dostęp do metody prywatny i pola. Zastanawiam się więc, w jaki sposób możemy ograniczyć dostępność, jeśli jest to częścią wymogu.

użytkownik245930
źródło
2
Kod o niskim zaufaniu nie może używać prywatnej refleksji (przynajmniej nie na innych zestawach, zapomniałem szczegółów). Kod pełnego zaufania może po prostu użyć wskaźników, aby ominąć wszelkie ograniczenia w tym procesie.
CodesInChaos
55
Modyfikatory dostępu prywatnego istnieją głównie po to, by informować programistów, że „nie używają tego spoza klasy, a jeśli naprawdę, to nie narzekaj, jeśli następna wersja złamie kod”, a nie tak ściśle wymuszoną funkcję bezpieczeństwa.
CodesInChaos
4
Użytkownicy mogą również po prostu załatać twój kod, aby zrobić co tylko zechce. Z częściowym wyjątkiem dotyczącym DRM (który nie jest wystarczająco silny, aby zapewnić trwałą ochronę), każdy, kto ma dostęp do twojej aplikacji (pliki binarne lub kod źródłowy) może z tym zrobić wszystko.
Brian
6
Czy to nie jest pytanie specyficzne dla języka? Refleksja działa inaczej w różnych językach. Zastanawiam się, czy to pytanie powinno mieć tag Java lub coś innego.
Wayne Conrad

Odpowiedzi:

54

Modyfikatory dostępu mają na celu informowanie programistów piszących kod o tym, jaki jest publiczny interfejs klasy. Nie są w żaden sposób środkiem bezpieczeństwa i nie dosłownie ukrywają ani nie zabezpieczają żadnych informacji.

JacquesB
źródło
33
To nie jest uniwersalna prawda. Cytując Erica Lipperta : „Modyfikatory dostępu w CLR są funkcjami bezpieczeństwa. Zasady dostępu są ściśle powiązane z systemami bezpieczeństwa i bezpieczeństwa typu.” W języku C # Reflection jest dostępne tylko dla kodu działającego z pełnym zaufaniem. Nie dotyczy to (i nie może) szkodliwych użytkowników systemu, którzy uruchamiają kod. Dotyczy to jednak złośliwych wtyczek.
Brian
5
@Brian Problem, o którym wspomina Brian, jest istotny, gdy system pozwala na uruchomienie kodu innej firmy bez pełnego zaufania. Przykłady obejmują piaskownice przeglądarki (np. Bardzo znienawidzony aplet), silnik aplikacji Google i platformę Azure . Byłoby naprawdę głupie, gdyby Azure nie pozwalał niezaufanemu kodowi na eksplorowanie szczegółów podstawowych bibliotek platformy.
JimmyJames
3
@Brian To nie w 100% poprawne - istnieją pewne operacje refleksji, które można wykonać w częściowo zaufanym kodzie; po prostu nie pozwala ci robić rzeczy takich jak dostęp do prywatnych pól.
Luaan,
1
@Brian Dopóki ktoś nie znajdzie luki w zabezpieczeniach lub inżynierii społecznej, która pozwala jej ominąć ograniczenia. Nie ma sensu próbować używać ich w ten sposób. To nie jest ich głównym celem.
jpmc26
31

Aby zacytować Herb Sutter na temat praw dostępu do klasy :

„Chodzi tutaj o ochronę przed Murphym vs. ochronę przed Machiavellim ... to znaczy ochronę przed przypadkowym niewłaściwym użyciem (co język robi bardzo dobrze) w porównaniu z celowym nadużyciem (co jest faktycznie niemożliwe). programista tak bardzo chce obalić system, znajdzie sposób „

Nemanja Trifunovic
źródło
2
Nie czasy, gdzie trzeba do piaskownicy kod niezaufanych, ale że jest to zadanie trudne. Ochrona przed błędem (Murphy) jest znacznie bardziej powszechnym przypadkiem.
Paul Draper,
#define private public(ignorując fakt, że tak naprawdę jest to niezdefiniowane zachowanie) i voila Mam pełny dostęp z zewnątrz do ograniczonej części twoich zajęć.
bolov
Ochrona przed celowym nadużyciem może być teoretycznie niemożliwa, ale jest to faktycznie możliwe, ponieważ sprawia, że ​​nadużycie jest wystarczająco trudne, że zdarza się bardzo rzadko. Ważne jest, aby mieć jasność na ten temat. W przeciwnym razie oprogramowanie nie byłoby w ogóle możliwe w sytuacjach takich jak krytyczne dla życia urządzenia medyczne.
MarkJ
@MarkJ. Uwaga Herb Suttera dotyczy umyślnego znęcania się przez programistę, który napisał klasę w pierwszej kolejności i być może jego kolegów z zespołu. Nie sądzę, że istnieje sposób, aby zapobiec tego rodzaju nadużyciom ze względu na funkcje językowe.
Nemanja Trifunovic
@bolov, że ten wyczyn zależy od języka. Podczas gdy preprocesory C / C ++ prawdopodobnie pozwoliłyby ci na ucieczkę, wszystko bez nich prawdopodobnie dałoby błąd „nie można użyć słów zastrzeżonych w #define”.
Dan bawi się Firelight
10

Nie, to faktycznie ważna zaleta. To, że niektórzy programiści nie uważali, że ktoś będzie potrzebował dostępu do jakiegoś stanu wewnętrznego, nie oznacza, że ​​nigdy nie pojawi się żaden uzasadniony przypadek użycia. W takich przypadkach użycie Refleksji do wykonania operacji na obiekcie może być ostatecznością. Musiałem użyć tej techniki więcej niż raz.

Mason Wheeler
źródło
1
Innymi słowy, jest to sposób na obejście prawdopodobnie uszkodzonego API - czy to z powodu niekompletnych wymagań, czy niepełnej implementacji.
Przywróć Monikę
4

Jeszcze bardziej ograniczasz dostępność, wchodząc o jeszcze jeden poziom: środowisko wykonawcze.

Nie wszystkie języki mają tę koncepcję, ale przynajmniej w Javie możesz użyć menedżera bezpieczeństwa, który zabrania udostępniania prywatnych pól. Możesz ręcznie zainstalować menedżera bezpieczeństwa w czasie wykonywania lub dodać zasadę bezpieczeństwa do pliku jar, który jest następnie zapieczętowany, aby zapobiec modyfikacji.

Więcej informacji o tym w Java: Reflection Security

Społeczność
źródło
3

O jakim odbiciu mówisz?

W wielu systemach refleksji obchodzenie enkapsulacji jest jawną możliwością, którą twój kod musi uzyskać i nie ma jej domyślnie.

Jeśli martwisz się o enkapsulację, prostym rozwiązaniem jest po prostu nie używanie systemu odbicia, który go nie chroni.

Jörg W Mittag
źródło
3

W Pythonie nie ma modyfikatorów dostępu. Konwencja polega na poprzedzeniu znakiem podkreślenia metod i zmiennych, do których nie oczekuje się dostępu z zewnątrz klasy. Czy to technicznie uniemożliwia ci dostęp do takiego pola z klasy innej firmy? Ani trochę; ale jeśli to zrobisz, jesteś sam i ryzykujesz zepsucie czegoś, bez możliwości obwiniania drugiej klasy.

W języku C # istnieją modyfikatory dostępu, ale są one jeszcze tylko konwencją - wymuszoną przez kompilator, ale nadal konwencją. Oznacza to, że technicznie nadal można uzyskać dostęp do zmiennych prywatnych i zmieniać je, albo poprzez odbicie, albo bezpośrednio manipulując pamięcią (jak robią to trenerzy gier ). Konsekwencja jest dokładnie taka sama: jeśli zmienne w twojej klasie zostaną zmienione przez Odbicie od innej klasy lub przez manipulowanie pamięcią przez inną aplikację, i to psuje coś w twojej klasie, to nie twoja wina.

Pamiętaj, że to oczywiście stwarza problemy bezpieczeństwa, w których strona trzecia może uzyskać dostęp do twoich danych; coś, co prowadzi do zaszyfrowanych wariantów ciągu i podobnych struktur danych. Ale ochrona twojego kodu przed takim użyciem jest bardziej związana z ograniczeniami systemu operacyjnego i dostępu na poziomie kodu i nie ma nic wspólnego z Reflection per se.

Arseni Mourzenko
źródło
2
Należy pamiętać, że w języku C # tylko w pełni zaufany kod może odzwierciedlać członków prywatnych. Pisanie bezpośrednio do pamięci procesu nadal działa, ale jest trudniejsze niż w kodzie natywnym.
Luaan,