Linux: Blokowanie dostępu do katalogów, plików i poleceń
W różnych sytuacjach następuje konieczność udzielenia dostępu do serwera zewnętrznym użytkownikom. Dobrym przykładem będzie utrzymywanie pewnej infrastruktury, na której inna firma ma za zadanie wdrożyć wybraną aplikację. Typowe aplikacje pisane na przykład w języku PHP w zakresie instalacji na docelowym środowisku nie wymagają pełnego dostępu do systemu jako root. Z reguły ich kod wystarczy umieścić w lokalizacji wskazanej w konfiguracji serwera WWW. Pliki z rozszerzeniem PHP będą przekazywane do interpretera tego języka, a rezultaty przedstawiane użytkownikowi. Podobnie działa to także w przypadku ASP.NET, gdzie jednak częściej używany jest system Windows i serwer IIS — w Linuxie odpowiednikiem jest projekt Mono, niestety nie wszystkie możliwości platformy .NET są wspierane.
Innym przypadkiem może być zwykłe udostępnienie wybranego katalogu klientowi, w ramach którego może pobierać czy przesyłać określone dane. Wtedy również nie ma żadnego uzasadnienia umożliwienie dostępu do całego systemu plików.
W systemach Linux możemy skutecznie izolować takich użytkowników od wrażliwej części środowiska. Przedstawione metody są ogólnie proste do realizacji. Chroot jest faktycznie bardziej zaawansowanym zagadnieniem, ale również ciekawym i w praktyce najmniej uciążliwym dla końcowego użytkownika.
SFTP
Korzystając z protokołu SFTP możemy bezpiecznie (szyfrowanie) pobierać i przesyłać dane do zdalnego hosta. SFTP jest bezpośrednio powiązany z protokołem SSH, który z kolei jest współczesnym (prekursorem był telnet) standardem w środowisku Linux. Używając SSH, zapewniamy zdalny dostęp do powłoki, a w konsekwencji możliwość wykonywania poleceń w systemie. Domyślnie autoryzujemy się z użyciem pary login i hasło, natomiast warto wykorzystywać w tym celu klucze.
W Linux usługi SFTP i SSH działają w ramach jednego daemon’a OpenSSH. Dlatego jeśli zamierzamy ograniczyć dla danego użytkownika dostęp wyłącznie do SFTP i zablokować możliwość wykonywania poleceń przez SSH, musimy dokonać zmian w pliku /etc/ssh/sshd_config. Znajduje się w nim poniższy fragment:
# override default of no subsystems
Subsystem sftp /usr/lib/openssh/sftp-server
Zastępujemy /usr/lib/openssh/sftp-server opcją internal-sftp, a następnie dopisujemy taką regułę (w tym przykładzie app to nazwa użytkownika, a ChrootDirectory wskazuje lokalizację katalogu domowego):
Match Group app
ChrootDirectory /home/users/app
ForceCommand internal-sftp
Pozwoli to na „zamknięcie” użytkownika w jego katalogu domowym, a także na zablokowanie dostępu SSH (dostęp możliwy wyłącznie z wykorzystaniem SFTP). Restartujemy usługę SSH:
sudo systemctl restart ssh
Na koniec musimy pamiętać o zmianie własności katalogu domowego naszego użytkownika. Domyślnie będzie to app:app, a potrzebujemy uzyskać root:app. W innym przypadku przy próbie połączenia SFTP będziemy otrzymywać błąd Broken pipe. Zmiany dokonujemy poleceniem chown:
sudo chown root:app /home/users/app
Można zauważyć, że wprowadzone zmiany są poprawne. SFTP został ograniczony do katalogu domowego, natomiast połączenie SSH nie dojdzie do skutku — otrzymamy komunikat This service allows sftp connections only.
Pewna wada tego sposobu to brak możliwości zapisu przez użytkownika danych w katalogu / przy połączeniu SFTP. Powodem jest ustawienie własności na root:app. Ciężko to jakkolwiek obejść, ponieważ zmiana praw na 775 będzie ponownie powodować błąd Broken pipe. Użytkownik wciąż jednak posiada pełny dostęp do wszelkich podkatalogów, o ile nie zmienialiśmy własności na tym poziomie (w naszym przypadku może zapisywać do katalogu public_html).
Warto dodać, że użytkownik cały czas może zalogować się “lokalnie” (tty), a inni użytkownicy mogą z użyciem polecenia su przelogować się na tego użytkownika. Rozwiązaniem jest przypisanie dla naszego użytkownika powłoki /sbin/nologin. Można to wykonać poleceniem usermod:
sudo usermod -s /sbin/nologin app
Próba przelogowania zakończy się teraz komunikatem This account is currently not available.
Opisana metoda jest świetnym wyjściem w sytuacji, gdy użytkownik nie potrzebuje dostępu do powłoki, a wyłącznie do przesyłania swoich plików czy odczytu udostępnionych w ten sposób zasobów. W innych przypadkach sprawdzą się podane w dalszej części alternatywy.
rbash
To specjalna wersja standardowej powłoki bash, która zawiera kilka ograniczeń, np. zablokowanie polecenia cd czy zmienną środowiskową SHELL w trybie read-only. Niestety nie działa dopełnianie poleceń bądź ścieżek (za pomocą klawisza Tab). W praktyce nie jest to osobny program, a tylko zwyczajny link symboliczny do powłoki bash właśnie o nazwie rbash:
ls -la /usr/bin/rbash
lrwxrwxrwx 1 root root 4 Mar 27 2022 /usr/bin/rbash -> bash
Nieprzypadkowo o tym wspominam, ponieważ potrzebujemy usunąć ten symlink. Jest to związane z możliwym obejściem, gdy podczas połączenia SSH użytkownik poprzez parametr -t wskaże ścieżkę do innej powłoki (np. /bin/bash). Po nawiązaniu połączenia zostanie załadowana wskazana powłoka zamiast przypisanej dla niego rbash.
Wykonujemy więc polecenia:
sudo unlink /usr/bin/rbash
sudo cp /usr/bin/bash .
Utworzyliśmy kopię pliku /usr/bin/bash, bo teraz dla każdej powłoki z pliku /etc/shells musimy poleceniem setfacl ustawić prawo tylko do odczytu dla blokowanego użytkownika:
sudo setfacl -m u:app:r /bin/sh
Ten proces można zautomatyzować:
powloki=$(grep -v '^#' /etc/shells)
while read -r powloka; do
sudo setfacl -m u:app:r "$powloka"
done <<< "$powloki"
Na koniec przenosimy utworzoną wcześniej kopię do pliku /usr/bin/rbash:
sudo mv bash /usr/bin/rbash
Zmieniamy także domyślną powłokę dla naszego użytkownika:
sudo usermod -s /usr/bin/rbash app
Podane wyżej instrukcje są wystarczające, ale możemy spróbować ograniczyć dostępne polecenia wyłącznie do kilku wybranych. Aktualnie użytkownik ma dostęp do wszystkich poleceń (oprócz cd) ze ścieżek zdefiniowanych w zmiennej PATH. Ich listę możemy uzyskać poprzez wyświetlenie zawartości tej zmiennej:
echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
Załóżmy, że użytkownik potrzebuje jedynie poleceń, które bez przeszkód pozwolą mu na pracę w powłoce. Proponuję przyjąć następujące:
cp, mv, mkdir, mysql, mysqldump, rm, rmdir, git, nano, ls, ln, cat, tee, pwd, grep, sed, head, less, tail, more, wget, curl, touch, dircolors
Aby osiągnąć zamierzony efekt, w pierwszej kolejności tworzymy osobny katalog przeznaczony na ww. binaria. Kopiujemy do niego odpowiednie pliki (wszystkie są w katalogu /usr/bin):
sudo mkdir /rbash_bin
sudo cp /usr/bin/{cp,mv,mkdir,mysql,mysqldump,rm,rmdir,git,nano,ls,ln,cat,tee,pwd,grep,sed,head,less,tail,more,wget,curl,dircolors,touch} /rbash_bin
Ustawiamy właściciela plików .profile i .bashrc w katalogu domowym naszego użytkownika na użytkownika root.
sudo chown root: /home/users/app/{.profile,.bashrc}
Zawartość zmiennej PATH jest ustalana na podstawie pliku /etc/profile. W moim systemie Debian pierwsze linie wyglądają tak:
# /etc/profile: system-wide .profile file for the Bourne shell (sh(1))
# and Bourne compatible shells (bash(1), ksh(1), ash(1), ...).
if [ "$(id -u)" -eq 0 ]; then
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
else
PATH="/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games"
fi
export PATH
Użytkownik root ma więc możliwość uruchamiania poleceń z lokalizacji /usr/local/sbin i /sbin (to również jest symlink do /usr/local/sbin), a reszta ze ścieżek widocznych po instrukcji else. Chcemy, aby ci wszyscy pozostali użytkownicy (z wyłączeniem jednak tych znajdujących się w grupie sudo) mogli wykonywać tylko polecenia z /rbash_bin. W tym celu wystarczy dodać warunek do instrukcji if i zmienić przypisanie zmiennej PATH po instrukcji else:
if groups|grep -q sudo || [ "$(id -u)" -eq 0 ]; then
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
else
PATH="/rbash_bin"
fi
export PATH
Działanie jest skuteczne, co potwierdzają próby uruchomienia kilku niedozwolonych poleceń:
chroot
Tak jak wspomniałem, utworzenie chroot to najtrudniejszy z opisanych tutaj sposobów, ale (jak to często bywa) równocześnie najbardziej interesujący. Chroot można określić jako „system wewnątrz systemu”, w którym izolujemy użytkowników czy nawet poszczególne aplikacje (o czym można przeczytać w poniższym dodatku). Z poziomu chroot nie ma dostępu do całości systemu, co oznacza potrzebę zbudowania tego środowiska tak, aby spełniało swoją rolę. W przypadku prostej izolacji użytkowników kroki są z reguły identyczne, natomiast niektóre programy użytkowe (jak chociażby git) wymagają dedykowanych zasobów, które niekoniecznie dodaliśmy do chroot podczas jego tworzenia. Wszystko wymaga testowania i weryfikacji działania.
Na początku ustawiamy właściciela katalogu domowego izolowanego użytkownika na root:
sudo chown root: /home/users/app
Użytkownik nie będzie miał dostępu do systemu plików, a co za tym idzie — także do ważnych katalogów. Musimy obudować chroot’owane środowisko, a w naszym przypadku jest to katalog /home/users/app. W pierwszej kolejności tworzymy katalog dev i kilka specjalnych plików poleceniem mknod:
sudo mkdir dev
sudo mknod -m 666 dev/null c 1 3
sudo mknod -m 666 dev/tty c 5 0
sudo mknod -m 666 dev/zero c 1 5
sudo mknod -m 666 dev/random c 1 8
Następnie tworzymy katalog bin, do którego kopiujemy potrzebne polecenia. Ich lista jest dłuższa niż w poprzednim przykładzie, ponieważ niektóre są zależne od pozostałych.
sudo mkdir bin
sudo cp /bin/{bash,cp,mv,mkdir,mysql,mysqldump,rm,rmdir,git,nano,ls,ln,unlink,cat,tee,pwd,grep,sed,head,less,tail,more,wget,curl,tar,tr,dirname,wc,perl,tput,basename,touch} bin
Teraz dość żmudny krok, ponieważ potrzebujemy skopiować biblioteki, z których korzystają podane polecenia. Skorzystamy z polecenia ldd. Przykład dla /usr/bin/bash:
Wylistowane zostały biblioteki używane przez powłokę bash wraz z ich lokalizacją. Te właśnie pliki musimy odtworzyć w naszym chroot dla każdego z podanych wyżej poleceń w katalogu lib. Wiele z nich jest wspólnych. Katalog lib64 można utworzyć na końcu, ponieważ ostatecznie i tak będzie zawierał tylko ten jeden plik ld-linux-x86-64.so.2.
W naszym przypadku po zakończeniu kopiowania plików katalogi lib i lib64 zawierają poniższe biblioteki:
W tym momencie chroot w swojej podstawowej formie jest gotowy. Niestety nie zadziałają edytory tekstu (przykładowo nano przy próbie uruchomienia zwróci błąd Error opening terminal: xterm-256color), a w samej powłoce bash nie zadziała skrót Ctrl+L czyszczący konsolę czy nie zobaczymy efektów użycia klawisza Backspace usuwającego wpisane znaki. Rozwiązaniem będzie utworzenie katalogu usr/share, do którego skopiujemy katalog /usr/share/terminfo oraz skopiowanie /lib/terminfo do naszego katalogu lib.
sudo mkdir -p usr/share
sudo cp -r /usr/share/terminfo usr/share
sudo cp -r /lib/terminfo lib
Poza tym nie działa rozwiązywanie nazw. Wystarczy jednak utworzyć katalog etc i skopiować do niego plik /etc/resolv.conf oraz skopiować bibliotekę libnss_dns.so.2 do lib/x86_64-linux-gnu:
sudo mkdir etc
sudo cp /etc/resolv.conf etc
sudo cp /usr/lib/x86_64-linux-gnu/libnss_dns.so.2 lib/x86_64-linux-gnu
Nie możliwe jest także używanie polecenia git, które przykładowo przy próbie sklonowania repozytorium zwraca:
warning: templates not found in /usr/share/git-core/templates
git: 'remote-https' is not a git command. See 'git --help'.
Rozwiązanie tych problemów jest trochę bardziej rozbudowane:
sudo cp -r /usr/share/git-core usr/share
sudo mkdir usr/lib
sudo cp -r /usr/lib/git-core usr/lib
sudo cp /usr/lib/x86_64-linux-gnu/libcurl.so.4 lib/x86_64-linux-gnu
sudo cp /usr/lib/x86_64-linux-gnu/libcurl.so.4.7.0 lib/x86_64-linux-gnu
sudo cp /usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4 lib/x86_64-linux-gnu
sudo cp /usr/lib/x86_64-linux-gnu/libssl.so.1.1 lib/x86_64-linux-gnu
sudo cp /usr/lib/x86_64-linux-gnu/libexpat.so.1.6.12 lib/x86_64-linux-gnu
sudo cp /usr/lib/x86_64-linux-gnu/libexpatw.so.1.6.12 lib/x86_64-linux-gnu
sudo cp -r /etc/ssl etc
Aby użytkownik był ograniczony po połączeniu z serwerem, niezbędne są zmiany w pliku /etc/ssh/sshd_config. Podobnie jak w przypadku konfiguracji SFTP w linii:
Subsystem sftp /usr/lib/openssh/sftp-server
zmieniamy /usr/lib/openssh/sftp-server na internal-sftp oraz dodajemy:
Match Group app
ChrootDirectory /home/users/app
Użytkownik został zamknięty w swojej izolowanej od pełnego systemu części. Ma dostęp wyłącznie do wybranych poleceń, nie ma możliwości chociażby odczytu danych nienależących do niego.
Dodatek: Apache w chroot
Na koniec chciałbym przedstawić proces izolacji serwera WWW Apache w środowisku chroot. Każda aplikacja uruchomiona w chroot nie ma dostępu do całości systemu operacyjnego, co zwiększa ogólne bezpieczeństwo. Chroot ma też zastosowanie, gdy różne aplikacje wymagają różnych wersji określonych zależności (dependency hell) — wtedy te aplikacje uruchamiamy w osobnych chroot, dzięki czemu rozwiązuje się problem niekompatybilności. Chociaż akurat w tej kwestii Docker będzie lepszym wyborem, przede wszystkim pod kątem zwykłej wygody korzystania.
Wyjątkowo trudnym i złożonym zadaniem byłoby ręczne kopiowanie wszelkich bibliotek czy katalogów, których wymaga działający serwer Apache. Wykorzystamy więc narzędzie debootstrap, które pobierze najnowszą wersję systemu Debian (bookworm). Postaramy się w jak największym stopniu zminimalizować to środowisko przy zachowaniu względnego komfortu zarządzania serwerem Apache z poziomu systemu.
Debootstrap można zainstalować z repozytorium lub pobrać plik DEB i wykonać instalację z użyciem dpkg (w repozytorium Debiana jest najnowsza wersja 1.0.128):
wget https://deb.debian.org/debian/pool/main/d/debootstrap/debootstrap_1.0.128+nmu2_all.deb
sudo dpkg -i debootstrap_1.0.128+nmu2_all.deb
Tworzymy “minimalny” obraz systemu:
sudo debootstrap --variant=minbase bookworm /home/users/web
Do katalogu /home/users/web zostaną pobrane odpowiednie dane. Wykonujemy chroot do niego (sudo chroot /home/users/web), po czym instalujemy Apache i PHP wraz z potrzebnymi rozszerzeniami. W razie potrzeby aktywujemy też niezbędne moduły Apache.
Naszym celem jest taka konfiguracja, aby do wprowadzania zmian w virtual hostach nie było potrzeby każdorazowego wchodzenia do tworzonego chroot. Dlatego też powinniśmy przenieść katalogi etc/apache2 i etc/php przykładowo do katalogu /etc w naszym systemie.
sudo mv etc/apache2 /etc
sudo mv etc/php /etc
Z katalogu etc usuwamy całą pozostałą zawartość oprócz podkatalogu init.d. Ponownie zamierzamy ograniczyć dostępne w chroot polecenia, stąd przenosimy także plik bin/php8.2. Tę samą czynność stosujemy do plików apache* z katalogu sbin.
Chroot nie ma dostępu do danych na poziomie systemu operacyjnego. Dlatego jeśli jakiekolwiek zasoby muszą być dostępne w chroot (np. klucz i certyfikat SSL czy wszelkie konfiguracje) musimy je zamontować poleceniem mount. Linki symboliczne nie zadziałają z oczywistego powodu.
sudo mkdir ssl
sudo mount --bind /ssl ssl
cd etc
sudo mkdir {apache2,php}
sudo mount --bind /etc/apache2 apache2
sudo mount --bind /etc/php php
Dodatkowo do etc musimy skopiować pewne pliki i katalog /etc/ssl:
sudo cp /etc/{resolv.conf,passwd,group,mime.types} etc
sudo cp -r /etc/ssl etc
Zmieniamy katalog domowy naszego użytkownika na wybrany z chroot. W tym przykładzie używam po prostu /app:
sudo usermod -d /app app
Przenosimy katalog domowy z oryginalnej lokalizacji i podobnie jak poprzednio zmieniamy właściciela na root.
Zarządzanie usługą Apache (start, stop, reload, restart) nie będzie możliwy bez katalogu /proc w chroot. Wystarczy podmontować ten katalog z naszego systemu:
sudo mount -t proc /proc proc
Bez dodania wpisów do pliku /etc/fstab po restarcie systemu wszystkie ustawione punkty montowania nie będą uwzględniane i będziemy zmuszeni wykonać te operacje ponownie. Nasze wpisy /etc/fstab mogą wyglądać w ten sposób:
/ssl /home/users/web/ssl none bind
/etc/apache2 /home/users/web/etc/apache2 none bind
/etc/php /home/users/web/etc/php none bind
proc /home/users/web/proc proc defaults,hidepid=2 0 0
Na tym etapie możemy przystąpić do minimalizacji tworzonego środowiska. Jak można zobaczyć, tych plików i katalogów w / jest zdecydowanie zbyt dużo.
Zajmiemy się najpierw katalogami z binariami. Ograniczmy dostępne polecenia do tych najbardziej przydatnych i niezbędnych w zwykłej pracy. Usuwamy symlink bin i sbin oraz katalog usr/bin:
sudo unlink bin
sudo unlink sbin
sudo rm -rf usr/bin
Tworzymy zwykły katalog bin (bez żadnego symlinku) i kopiujemy do niego konieczne polecenia:
sudo cp /bin/{bash,sh,env,echo,id,mktemp,expr,chmod,chown,readlink,sleep,cp,mv,mkdir,mysql,mysqldump,rm,rmdir,git,nano,ls,ln,unlink,cat,tee,pwd,grep,egrep,sed,head,less,tail,more,wget,curl,tar,unzip,tr,dirname,wc,perl,tput,basename,touch,awk,pidof,ps} bin
Może nie wszystkie z nich wydają się absolutnie użyteczne dla zwykłego użytkownika, ale bez nich nie będziemy w stanie poprawnie zarządzać usługą Apache. Nie zapominamy też o pliku binarnym php, który wcześniej przenieśliśmy do tymczasowego miejsca. Z kolei pliki apache* przenosimy do usr/sbin.
Wykonujemy dalsze oczyszczanie:
sudo rm -rf {boot,dev,home,media,mnt,opt,root,srv,sys}
Tworzymy pusty katalog root. Niezbędny będzie ponadto katalog dev, gdzie analogicznie jak poprzednio tworzymy pliki specjalne:
sudo mknod -m 666 dev/null c 1 3
sudo mknod -m 666 dev/tty c 5 0
sudo mknod -m 666 dev/zero c 1 5
sudo mknod -m 666 dev/random c 1 8
sudo mknod -m 666 dev/urandom c 1 9
Polecenie git ponownie będzie potrzebować pewnych katalogów i biblioteki:
sudo cp -r /usr/share/git-core usr/share
sudo cp -r /usr/lib/git-core usr/lib
sudo cp /usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4 lib/x86_64-linux-gnu
sudo cp /usr/lib/x86_64-linux-gnu/libldap_r-2.4.so.2 lib/x86_64-linux-gnu
sudo cp /usr/lib/x86_64-linux-gnu/liblber-2.4.so.2 lib/x86_64-linux-gnu
systemctl nie działa w chroot, a wywoływanie service apache2 <akcja> i tak odwołuje się do skryptu apache2ctl, który używa systemctl. W tym skrypcie (usr/sbin/apache2ctl) widnieje poniższy fragment:
need_systemd=false
if [ -z "$APACHE_STARTED_BY_SYSTEMD" ] ; then
case "$(readlink -f /proc/1/exe)" in
*systemd*)
need_systemd=true
;;
*)
;;
esac
fi
Wewnątrz bloku case wystarczy przypisać false do need_systemd i ta prosta modyfikacja rozwiązuje opisaną trudność.
Zresztą w samym katalogu usr/sbin znajduje się 144 plików binarnych. Możemy je wszystkie (oprócz tych zaczynających się od a2, apache i service) usunąć. Dodatkowo w katalogach usr i var będzie kilka pustych katalogów nadających się właśnie do usunięcia. Nie trzeba tego wykonywać ręcznie, można posłużyć się poleceniem find:
sudo find -maxdepth 1 -type d -empty -delete
Prawdopodobnie po tych wszystkich czynnościach pozostaną nam nieaktualne dowiązania symboliczne lib32 i libx32. Można je bezpiecznie usunąć.
Bardzo istotna kwestia to zarządzanie usługą. Najprostszym podejściem będzie napisanie dwóch prostych skryptów — start.sh i reload.sh — które odpowiednio uruchomią Apache po restarcie systemu i przeładują konfigurację (co jest ważne po działaniu logrotate, w innym wypadku Apache będzie próbował zapisywać logi do nieistniejących plików). Skrypty można umieścić nawet w katalogu głównym chroot (u nas to /home/users/web).
start.sh
#!/bin/bash
/etc/init.d/apache2 start
reload.sh
#!/bin/bash
/etc/init.d/apache2 reload
Chroot jest gotowy, pozostaje zadbać o automatyczny start usługi oraz rotowanie logów. Trzeba też dodać konfigurację virtual host. Sprawę uruchamiania załatwi zwykłe zadanie cron (dla użytkownika root i, co oczywiste, dodane w naszym systemie):
@reboot /usr/sbin/chroot /home/users/web "./start.sh"
Konfiguracja logrotate może ograniczyć się do:
/home/users/web/*/logs/*.log {
rotate 14
daily
compress
postrotate
/usr/sbin/chroot /home/users/web "./reload.sh"
endscript
}
Zmianami w serwerze Apache możemy zarządzać standardowo poprzez pliki w katalogu /etc/apache2 (który wcześniej przenieśliśmy z chroot). Wymagane będzie dopisanie ServerName localhost do pliku /etc/apache2/apache2.conf. Konfiguracja SSH jest analogiczna jak przy zwykłym chroot dla użytkownika.
Uruchomienie Apache z PHP w chroot ma tę dobrą właściwość, że cały kod wykonywany jest na poziomie chroot. Widać to nawet na przykładzie ścieżek. Spoza chroot wiemy, że pliki strony znajdują się w lokalizacji /home/users/web/app/public_html/app.test.local. Tymczasem aplikacja nie jest (i nie musi) być tego świadoma:
Samo środowisko zostało dość dokładnie zminimalizowane:
Czy ten artykuł był pomocny?
Oceniono: 2 razy