Mechanizmy bezpieczeństwa - Ruby vs Python
Posted by Jarosław Zabiełło Fri, 10 Mar 2006 21:37:00 GMT
W języku Ruby (mimo jego wielkiego dynamizmu) kwestia bezpieczeństwa została potraktowana poważnie. Ruby posiada różne mechanizmy umożliwiające kontrolę nad bezpieczeństwem kodu. Generalnie są to 3 różne mechanizmy.
- Zakresy metod: private, protected i public.
- Możliwość nieodwracalnego zamrożenia dowolnego obiektu.
- Możliwość nieodwracalnego ustawiania poziomów bezpieczeństwa.
Zakresy private, protected, public
- Metody publiczne moga być wywoływane przez kogokolwiek. Domyślnie wszystkie metody są publiczne (poza konstruktorem initialize który zawsze jest prywatny)
- Metody chronione (protected) mogą być wywoływane tylko przez obiekty w tej samej klasie i klasach potomnych.
- Metody prywatne mogą być wywoływane tylko w kontekście bieżącego obiektu. Nie można wywoływać metod prywatnych innego obiektu.
Np.:
class C
public
def publiczna
p "Metoda publiczna"
end
def get_chroniona
chroniona
end
def get_prywatna
prywatna
end
protected
def chroniona
p "Metoda chroniona"
end
private
def prywatna
p "Metoda prywatna"
end
end
c = C.new
c.publiczna # => Metoda publiczna
c.get_chroniona # => Metoda chroniona
c.get_prywatna # => Metoda prywatna
c.chroniona # => protected method `chroniona' called for #<C:0x28e6300> (NoMethodError)
c.prywatna # => private method `prywatna' called for #<C:0x28e62e8> (NoMethodError)Dla porównania, w Pythonie wszystkie metody są publiczne. Efekt metod prywatnych i chronionych uzyskuje się za pomocą konwencji. Metody prywatne mają prefiks dwóch underscorów, a chronionie – jeden underscore. Oczywiście nadal są one formalnie publicznie ale dostęp do nich (szczególnie do metod “prywatnych” jest utrudniony)
class C(object):
def publiczna(self):
print "Metoda publiczna"
def get_chroniona(self):
self._chroniona()
def get_prywatna(self):
self.__prywatna()
def _chroniona(self):
print "Metoda chroniona"
def __prywatna(self):
print "Metoda prywatna"
c = C()
c.publiczna()
c.get_chroniona() # => Metoda chroniona
c.get_prywatna() # => Metoda prywatna
c._chroniona() # => Metoda chroniona
c._C__prywatna() # => Metoda prywatna
c.__prywatna() # => AttributeError: 'C' object has no attribute '__prywatna'Python wychodzi z innych przesłanek niż Ruby. Zakłada, że “jesteśmy dorośli i wiemy co chcemy robić”. Tzn. utrudnia popełnienie pomyłki przypadkowego dostępu do metody “prywatnej” za pomocą zmodyfikowania nazwy która da dostęp do takiej metody. Jednak jak ktoś, chce to Python nie będzie utrudniał. Można dostać się do każdej metody. Jak zobaczymy dalej (przy omawianiu poziomów bezpieczeństwa Rubiego), ta zasada spowodowała daleko idące konsekwencje dla kwestii bezpieczeństwa kodu Pythona.
Zamrażanie obiektów
Jeśli chodzi o kwestie zamrażania obiektów, to opisuję to w artykule o dynamice klas Python nie posiada jednak aż tak eleganckiego mechanizmu co Ruby. Da się co prawda przyblokować zmiany w obiekcie, ale trzeba sięgnąć po bardziej zaawansowane mechanizmy:
class ImmutableClass(type):
def __setattr__(cls, name, value):
raise AttributeError, "'%s' is immutable" % cls.__name__
class C(object):
def hello(self):
return 'Hello World!'
__metaclass__ = ImmutableClass # blokada zmiany
def hello2(self): return 'Blah!'
c = C()
print c.hello() # => Hello World!
C.hello = hello2 #=> AttributeError: 'C' is immutable
print c.hello() # => Hello World!Poziomy bezpieczeństwa
Jedną z ciekawych cech języka Ruby jest możliwość uruchamiania kodu na różnym poziomie bezpieczeństwa. Załóżmy np, że chcemy stworzyć (w najprostszy możliwy sposób) kalkulator który następnie udostępnimy na stronie internetowej. Przykładowy kod (na podst. PixAxe2) mógłby wyglądać np. tak:require 'cgi'
cgi = CGI.new('html4')
# pobierz warto z pola formularza 'wyrazenie'
expr = cgi['wyrazenie'].to_s
begin
result = eval(expr)
rescue Exception => detail
# obsłuż złe wyrażenie
end
# wyświetl wynik dla użytkownikasystem("rm *")Cały nasz kod zostanie skasowany! Na szczęście Ruby udostępnia mechanizm uruchamiania kodu w specjalnym trybie tak, aby kod nie był w stanie zbytnio rozrabiać. Poziom Rubinowej paranoi bezpieczeństwa określa zmienna globalna $SAFE. Może ona przyjmować następujące wartości:
- 0 Brak mechanizmów zabezpieczeń. Wartość domyślna.
- >= 1 Ruby zabrania uzywanie danych w potencjalnie niebezpiecznych operacjach
- >= 2 Ruby zabrania ładowanie innych skryptów z dostępnych globalnie miejsc
- >= 3 Wszystkie nowo stworzone obiekty są oznakowane jako niebezpieczne
- >= 4 Ruby dzieli uruchamiany program tak, że obiekty nie oznaczone jako niebezpieczne również nie mogą być modyfikowane.
Domyślna, zerowa wartość $SAFE jest wystarczająca w większości przypadków. Jednak, gdy skrypt Rubiego jest uruchamiany z ustawionym atrybutem suid lub setgid (co pod uniksem umożliwia uruchomienie skryptu w kontekście innego użytkownika) lub, gdy ruby pracuje w trybie modułu apache’a (mod_ruby), to poziom bezpieczeństwa jest automatycznie podnoszony do 1. Poziom bezpieczeństwa można także ustawić za pomocą parametru -T z wiersza poleceń lub poprzez przypisanie zmiennej $SAFE innej wartości. Przy czym, nie jest możliwe zmniejszenie raz ustawionego poziomu bezpieczeństwa aż do końca działania skryptu.
Bieżąca wartość $SAFE jest dziedziczona przez wszystkie nowo tworzone wątki. Jednakże wewnątrz każdego wątka, wartość zmiennej globalnej $SAFE może być zmieniana bez wpływu na tą wartość w innym wątku. Ta cecha pozwala na budowanie bezpiecznych piaskownic (sandbox), obszarów w których można odpalać potencjalnie niebezpieczny kod bez ryzyka, że wpłynie on na resztę aplikacji czy systemu. Np.File.new(filename, 'w').write('niebezpieczny kod')
Thread.start do
$SAFE = 4
load(filename, true)
endDla porównania, Python w ogóle nie posiada takich mechanizmów. Na domiar złego, okazało się, że (obecny we wcześniejszych wersjach Pythona) moduł Bastion okazał się dziurawy Został usunięty w biblioteki podstawowej i jak na razie Python nie posiada już nic w tym temacie do zaoferowania w zamian.


Kanały IRC![[Dilber w Onecie]](/images/larry.png)


metody prywatne też mogą być wywoływane z zewnątrz:
i ciekawostka:
oj, jak mam quotować w typo ?
Dodałem ci kolorowanie. Zobacz dostępne opcje dla Textile.