niedziela, 29 listopada 2009

Linux w AD

Oprócz samego Kerberosa, potrzebna będzie SAMBA i dostarczane wraz z nią narzędzia - w szczególności winbindd. Cały proces możemy podzielić na dwa etapy. Pierwszym jest przyłączenie stacji/serwera do domeny; drugim skonfigurowanie zasad uwierzytelniania przy użyciu loginu domenowego. Przyłączanie będzie wyglądało trochę inaczej w przypadku serwerów, inaczej w przypadku stacji roboczych. Przede wszystkim dlatego, że rzadko kiedy na serwerach wykorzystuje się nakładki graficzne np. KDE czy Gnome.

Zacznijmy więc od serwerów. W naszym przykładzie działamy na serwerze pod kontrolą CentOS 4.5 Server. Zakładamy, że Samba jest już zainstalowana. Możemy przystąpić do poszczególnych kroków konfiguracyjnych. Na pierwszy rzut Kerberos. W każdej dystrybucji Linuksa natywnie dostępny jest klient Kerberosa. Jego parametry konfiguruje się za pomocą pliku /etc/krb5.conf.

[logging]
default = FILE:/var/log/krb5libs.log
kdc = FILE:/var/log/krb5kdc.log
admin_server = FILE:/var/log/kadmind.log

[libdefaults]
default_realm = NASZTEST.PL
dns_lookup_realm = true
dns_lookup_kdc = true

[realms]
NASZTEST.PL = {
kdc =dc.nasztest.pl
}

[kdc]
profile = /var/kerberos/krb5kdc/kdc.conf

[appdefaults]
pam = {
debug = false
ticket_lifetime = 36000

Jest to okrojona wersja konfiguracyjna krb5.conf, ale do naszych potrzeb wystarczająca. Koniecznie trzeba pamiętać o rozróżnieniu na duże i małe litery - bez tego usługa może nie działać prawidłowo. Ponieważ Kerberos jest bardzo wrażliwy na rozbieżności czasowe należy też zadbać o ustawienie synchronizacji czasu z serwerem czasu (polecenie ntpdate). Dla wygody warto wywoływać synchronizację automatycznie w określonych odstępach czasu za pomocą systemowego cron-a.

Kolejny krok to konfiguracja samej SAMBY. Tutaj zmian dokonuje się w pliku /etc/samba/smb.conf. Poniżej znajduje się lista parametrów w sekcji [global], które koniecznie należy zmodyfikować lub dopisać:

workgroup = NASZTEST # tutaj wpisujemy nazwę domeny
security = ads
encrypt passwords = yes
realm = NASZTEST.PL
password server = DC.NASZTEST.PL
winbind separator = +
winbind enum users = yes
winbind enum groups = yes
winbind nested groups = yes

Pozostała część konfiguracji SAMBY to już inna historia.

Teraz można podłączyć serwer do domeny:

# net ads join -U Administrator
Administrator's password:
Using short domain name - NASZTEST
Joined 'LINSERWER' to realm 'NASZTEST.PL'

Warto jeszcze sprawdzić, czy faktycznie zostaliśmy dołączeni do domeny:

# wbinfo -t
checking the trust secret via RPC calls succeeded
# wbinfo net ads testjoin
Join is OK

net ads join -U sdniemczok

wbinfo -t
wbinfo -g
wbinfo -u

np.
chown -R root.AD\\di install/

Jeżeli teraz uruchomimy przystawkę zarządzania użytkownikami i komputerami Active Directory (na kontrolerze domeny), to w sekcji "Komputery" powinniśmy zobaczyć nowo dodany serwer. Teraz pora na aktywację usługi winbind - korzysta ona z Linuksowej implementacji odwołań Microsoftowego RPC. W tym celu trzeba zmodyfikować plik /etc/nsswitch.conf odpowiedzialny za dostarczanie źródeł rozwiązywania nazw np. hostów, aliasów pocztowych, użytkowników. Wskazanie winbind jako źródła informacji pozwala na powiązanie ich z domeną Windows. Musimy zatem w pliku nsswitch.conf dokonać dwóch zmian:

passwd: files winbind
group: files winbind

----------------------------------------------------------------------------------------------
cd.2 EN

Kerberos

The first step in joining an Active Directory domain is to install and configure Kerberos. See Samba/Kerberos for details.

Join AD domain

Required software

You need to install the winbind and samba packages. The packages smbfs and smbclient are useful for mounting network shares and copying files.

IconsPage/IconNote.png The package smbfs is optional, but includes useful client utilities, including the smbmount command. Also useful is the smbclient package, which includes an FTP-like client for SMB shares.

Join

The first step in joining the Active Directory domain is to edit /etc/samba/smb.conf:

file: /etc/samba/smb.conf

[global]
security = ads
realm = LAB.EXAMPLE.COM
password server = 10.0.0.1
# note that workgroup is the 'short' domain name
workgroup = LAB
# winbind separator = +
idmap uid = 10000-20000
idmap gid = 10000-20000
winbind enum users = yes
winbind enum groups = yes
template homedir = /home/%D/%U
template shell = /bin/bash
client use spnego = yes
client ntlmv2 auth = yes
encrypt passwords = yes
winbind use default domain = yes
restrict anonymous = 2

IconsPage/IconNote.png Adding valid users = @"Domain Users" to the [global] section will allow all Domain Users to see all of the shares avaliable without a password. This is the equivlient to allowing "Everyone" to read all shares. If you want to restrict reading a share then you will have to specify valid users for that share.

IconsPage/IconNote.png The "winbind use default domain" parameter is useful in single-domain enterprises and causes winbind to treat any username that isn't qualified with a domain name as a username in the domain to which winbind is joined. Omit this parameter if you are concerned about confusion between local accounts on your systems and accounts in the default domain. The "winbind separator" directive is optional, and the default value is the usual backslash "\" Domain and User separator. You can use "+" if you know of a specific reason "\" will not work in your environment.

Be sure to restart the Samba and Winbind services after changing the /etc/samba/smb.conf file:

sudo /etc/init.d/winbind stop
sudo /etc/init.d/samba restart
sudo /etc/init.d/winbind start

Request a valid Kerberos TGT for an account using kinit, which is allowed to join a workstation into the AD domain. Now join to the domain, if the ticket was valid you should not need to supply a password - even if prompted you should be able to leave it blank.

IconsPage/IconNote.png This next step gave me the error: kinit(v5): Cannot resolve network address for KDC in realm LAB.EXAMPLE.COM while getting initial credentials even though nslookup win2k3 and host 10.0.0.1 would both return the correct entries. To correct this problem, I had to edit my /etc/hosts file and add the following to it: 10.0.0.1 win2k3.lab.example.com

sudo kinit Administrator@EXAMPLE.COM
sudo net ads join
Using short domain name – LAB
Joined 'linuxwork' to realm 'LAB.EXAMPLE.COM'

IconsPage/IconNote.png If the Kerberos auth was valid, you should not get asked for a password. However, if you are not working as root and are instead using sudo to perform the necessary tasks, use the command sudo net ads join -U username and supply your password when prompted. Otherwise, you will be asked to authenticate as root@LAB.EXAMPLE.COM instead of a valid account name. You can also supply a password if you don't want to get prompted. Just use net ads join -U % for this. Maybe it's useful for unattended installations where you want to add machines to an AD automatically.

IconsPage/IconNote.png If your Active Directory server is not running DDNS as well (eg. if you're running a separate DNS server) you may get the error:

sudo net ads join
Failed to join domain: failed to find DC for domain LAB.EXAMPLE.COM

To fix this, specify the AD server to the "net join" command:

sudo net ads join -S WIN2K3 -U %

You'll get a warning about not being able to update DNS, but you will successfully join the AD!

Testing

IconsPage/IconNote.png Using a clean install of 10.04, I did not have to modify any PAM files to get authentication working. I had to edit common-session to get the home directories created, but that is it.

Setup Authentication

nsswitch

file: /etc/nsswitch.conf

passwd:         compat winbind
group: compat winbind
shadow: compat

IconsPage/IconNote.png I needed to add hosts: files dns to /etc/nsswitch.conf to avoid the settings in /etc/hosts to be ignored.

IconsPage/IconNote.png Don´t forget to restart winbind again after editing /etc/nsswitch.conf!!!

Testing

You can check that the Domain has successfully been joined by:

wbinfo -u

You should get a list of the users of the domain.

IconsPage/IconNote.png I needed to make shadow: compat winbind in /etc/nsswitch.conf to make wbinfo -u work.

And a list of the groups. Be patient these queries can take time.

wbinfo -g

Check Winbind nsswitch module with getent.

IconsPage/IconNote.png This step may or may not work. If you only see local users, try connecting with a Windows machine anyways. (Tested under Ubuntu 9.10 x64)

sudo getent passwd

root:x:0:0:root:/root:/bin/bash
...
LAB+administrator:x:10000:10000:Administrator:/home/LAB/administrator:/bin/bash
LAB+gast:x:10001:10001:Gast:/home/LAB/gast:/bin/bash
...

Note that the domain name (here, "LAB+") is displayed by getent only if you have not set winbind use default domain = yes in smb.conf.

sudo getent group

root:x:0:
daemon:x:1:
bin:x:2:
...
LAB+organisations-admins:x:10005:administrator
LAB+domänen-admins:x:10006:manuel,administrator
LAB+domänen-benutzer:x:10000:
LAB+domänen-gäste:x:10001:
LAB+linux-admins:x:10004:manuel
...

PAM

With this config you can access the workstation with local accounts or with domain accounts. On the first login of a domain user a home directory will be created. This PAM configuration assumes that the system will be used primarily with domain accounts. If the opposite is true (i.e., the system will be used primarily with local accounts), the order of pam_winbind.so and pam_unix.so should be reversed. When used with local accounts, the configuration shown here will result in a failed authentication to the Windows/Samba DC for each login and sudo use. This can litter the DC's event log. Likewise, if local accounts are checked first, the /var/log/auth.log will be littered with failed logon attempts each time a domain account is accessed.

Note: You can use pam-auth-update to add the necessary entries for winbind authentication.

sudo pam-auth-update

This PAM configuration does not acquire a Kerberos TGT at login. To acquire a ticket, use kinit after logging in, and consider using kdestroy in a logout script.

file: /etc/pam.d/common-account

account sufficient       pam_winbind.so
account required pam_unix.so

file: /etc/pam.d/common-auth

auth sufficient pam_winbind.so
auth sufficient pam_unix.so nullok_secure use_first_pass
auth required pam_deny.so

IconsPage/IconNote.png On a Ubuntu 7.10 (Gutsy Gibbon) and 9.04 (Jaunty Jackalope) systems, these changes to pam.d/common-auth result in not being able to log in as a local user, for example by ssh. Your luck may be better, but test immediately just in case.

This one allows login for AD users and local users (tested with Ubuntu 9.10)

file: /etc/pam.d/common-auth

auth sufficient pam_unix.so nullok_secure
auth sufficient pam_winbind.so require_membership_of=domänen-admins use_first_pass
auth requisite pam_deny.so
auth required pam_permit.so
auth optional pam_ecryptfs.so unwrap

IconsPage/IconNote.png ecryptfs does not work with AD users. Login is successful with local users and AD users which are members of AD group domänen-admins

file: /etc/pam.d/common-session

session required pam_unix.so
session required pam_mkhomedir.so umask=0022 skel=/etc/skel

file: /etc/pam.d/sudo

auth sufficient pam_winbind.so
auth sufficient pam_unix.so use_first_pass
auth required pam_deny.so

@include common-account

Final configuration

Each domain needs a directory in /home/.

sudo mkdir /home/LAB

One last thing

If you want to be able to use an active directory account to manage your Ubuntu box, you need to add it to the sudoers file. For that, you will need to edit the file /etc/group an add your username to the admin group and whatever other group you need(plugdev,audio,cdrom just to mention a few). it will be like:

.......
admin:x:117:olduser,ActiveDirectoryUser
.......

Where, olduser, is your current linux user and, ActiveDirectoryUser, is the new administrator. Another way to make a Domain Group a sudoer in your ubuntu is to edit the file /etc/sudoers (using the command 'visudo') and add the following line

%adgroup        ALL=(ALL) ALL

Where, adgroup, is a group from your active directory. Keep in mind that spaces in the group name are not allowed. You can use '%domain\ admins', without quotes.

Usage

Logon with DOMAIN+USERNAME, unless you included "winbind use default domain" in your smb.conf, in which case you may log in using only USERNAME.

login: LAB+manuel
Password: *****
...
LAB+manuel@linuxwork:~$

Automatic Kerberos Ticket Refresh

To have pam_winbind automatically refresh the kerberos ticket

Add the winbind refresh tickets line to smb.conf :

file: /etc/samba/smb.conf

#       winbind separator = +
winbind refresh tickets = yes
idmap uid = 10000-20000

And modify /etc/pam.d/common-auth:

file: /etc/pam.d/common-auth

auth sufficient pam_winbind.so krb5_auth krb5_ccache_type=FILE
auth sufficient pam_unix.so nullok_secure use_first_pass
auth required pam_deny.so

Troubleshooting

If the Winbind PAM module in /var/log/auth.log says that the AD-user is not existing restart winbind. It might be best to restart the whole workstation.

sudo /etc/init.d/winbind restart

If when logging into the machine one gets a "no logon servers" error winbind\samba may not be starting properly. Try restarting them manually, and then logging in.

-If a manual restart works, then to fix this issue one needs to change scripts S20samba and S20winbind to S25samba and S25winbind in the /etc/rc2.d, rc3.d, rc4.d, rc5.d folders. The understanding is that this causes samba and winbind to startup later in the boot order for each runlevel. So that they start after S24avahi-daemon. If you then find that you must wait a bit before you can log in, you need to set "winbind enum users" and "winbind enum groups" in /etc/samba/smb.conf to 'no'.

name service cache daemon

The name service cache daemon (nscd) can interfere with winbind, as winbind maintains its own cache. Remove it.

sudo apt-get remove nscd

Some names or groups are resolved with getent, but others are not

The range of your idmap parameter is not wide enough to encompass all the users or groups

idmap uid = 16777216-33554431
idmap gid = 16777216-33554431

Adding more than one Linux machine to a Windows network

The above procedure allows you to add as many Linux machines as you like. However, the UID assigned to a given user may not be the same across all the machines. It created file ownership & rights issues when files/folders are shared between these machines. See Question #21806 on https://answers.launchpad.net/ubuntu/ for details. Therefore it is advisable to specify the UID mapping method

idmap backend = rid:YOURDOMAIN=70000-1000000
idmap uid = 70000-1000000
idmap gid = 70000-1000000
winbind use default domain = yes
security = ADS

The newer syntax is (with old style you can get NT_STATUS_OBJECT_NAME_COLLISION in /var/log/samba/log.winbindd)

idmap domains = YOURDOMAIN
idmap config YOURDOMAIN:backend = rid
idmap config YOURDOMAIN:range = 70000-1000000
winbind use default domain = yes
security = ADS

SQUID no cache example pages

acl NoCacheURL dst_domain www.example.com
cache deny NoCacheURL

poniedziałek, 26 października 2009

Rsync

rsync -avz /root/backup / backup

rsync.exe -qartuz --force --delete 10.173.231.201::backup/* /cygdrive/c/backup/

rsyncd.conf


log file = /var/log/rsyncd.log
pid file = /var/run/rsyncd.pid
lock file = /var/run/rsync.lock

[backup]
path = /backup/
comment = backup
read only = yes
use chroot = no
charset = utf-8
uid = root
gid = root
hosts allow = 10.173.231.0/24

piątek, 23 października 2009

Jak zmienić hasło użytkownika w MySQL-u?

Jeśli korzystamy z konta administratora (root) i nigdy nie zmienialiśmy jego hasła, należy to zrobić komendą:
mysqladmin -u root password NOWE_HASLO

Jeżeli chcemy zmienić hasło użytkownika, który ma już jakieś ustanowione, należy to zrobić komendą:
mysqladmin -u NAZWA_UZYTKOWNIKA
 -p STARE_HASLO NOWE_HASLO

Zmiana już ustanowionego hasła administratora jest oczywiście możliwa przez:
mysqladmin -u root -p STARE_HASLO NOWE_HASLO

Jak przekierować porty za pomocą SSH?

Przekierowania mogą być realizowane przez zaszyfrowane tunele i dlatego są uważane za dobry sposób zabezpieczenia zawartości ruchu sieciowego. Jest to połączenie routingu i przepisania pakietów – dlatego, że aby dostarczyć pakiety danych do docelowej usługi sieciowej, trzeba zmienić ich docelowy IP, docelowy port lub jedno i drugie. Przepisanie takie musi być z punktu widzenia użytkownika przezroczyste, tak by gdy sądzi on, że łączy się z portem 23, a faktycznie połączenie następuje na porcie 2323, nie było różnicy w funkcjonowaniu usługi.

Przekierowanie można uzyskać za pomocą ustawienia reguł dla zapory sieciowej albo też za pomocą oprogramowania takiego jak SSH. Zaletą wykorzystania SSH jest to, że możemy to zrobić bez konieczności zmiany konfiguracji usług systemowych (do czego możemy też nie mieć uprawnień), a w dodatku nasze połączenia będą zaszyfrowane.

Załóżmy, że chcemy przekierować połączenia z portu 2323 naszego komputera na port 23 w maszynie zdalny.host.net:
ssh -L 2323:localhost:23 zdalny.host.net. -o "KeepAlive yes"


Flaga -L mówi klientowi SSH, by uruchomić lokalny tunel pomiędzy podanymi portami i maszynami, flaga -o zaś, by podtrzymać połączenie, nawet jeśli nie ma na nim żadnego ruchu sieciowego.

Po uruchomieniu połączenia zostajemy poproszeni o zalogowanie się do zdalnego systemu. Po zalogowaniu pomiędzy maszynami localhost i zdalny.host.net zostaje uruchomiony szyfrowany tunel. Teraz by np. uzyskać dostęp do usługi telnet na maszynie zdalny.host.net (normalnie niedostępnej), wystarczy wydać polecenie:
telnet localhost 2323


UWAGA: Przekierowanie portów wymaga praw administratora tylko wtedy, gdy otwieramy tunel do portów uprzywilejowanych, o numerze od 0 do 1023. Podany w przykładzie port 2323 może być oczywiście wykorzystany przez każdego użytkownika.

Zamiast usługi telnet możemy w ten sposób przekierować np. połączenia FTP czy SCP.

HTTPS: jak uruchomić SSL w serwerze Apache?

Potrzebna nam będzie działająca instalacja serwera Apache oraz pakiet OpenSSL. Apache powinien dysponować modułem mod_ssl. Może on być albo wkompilowany w serwer, albo ładowany oddzielnie. O tym, że mod_ssl został wkompilowany w serwer, możemy się przekonać, wydając polecenie apache2 -l (lub httpd -l – w zależności od systemu, na jakim pracujemy). Jeśli zaś mod_ssl jest niezależnym modułem, to w katalogu z modułami Apache'a powinien znaleźć się plik mod_ssl.so. Jeżeli jednak mod_ssl nie występuje w żadnym z tych miejsc, musimy albo zrekompilować serwer, albo poszukać pakietu zawierającego ten moduł.
Generowanie klucza

Na początku należy stworzyć klucz i certyfikat, za pomocą którego dane będą szyfrowane i deszyfrowane z serwera WWW. Najlepiej wykorzystać w tym celu generator (pseudo)losowych znaków. Jeden z najlepszych generatorów liczb pseudolosowych można znaleźć w Sieci – to serwis www.random.org. Możemy w nim wygenerować łańcuchy dowolnej długości, składające się z cyfr oraz małych i dużych liter. Wygenerowany łańcuch zapisujemy do pliku, którym następnie „nakarmimy” generator liczb losowych OpenSSL-a.

Robimy to za pomocą komendy:
openssl genrsa -des3 -rand plik.txt -out serwer.klucz 1024

OpenSSL zapyta o hasło – może być ono dowolne. Problem tylko z tym, że przy każdym restarcie Apache'a będziemy musieli je podawać. Jeśli nie chcemy uwierzytelniać klucza serwera przy każdym jego uruchomieniu, można usunąć hasło za pomocą komendy:

openssl rsa -in serwer.klucz -out serwer.bezszyfru

Po podaniu klucza podanego w poprzednim kroku openssl generuje nam plik serwer.bez zawierający niezaszyfrowany klucz serwera.

Teraz, mimo że sami będziemy sobie podpisywali certyfikat, należy wygenerować żądanie podpisu certyfikatu. Robimy to komendą:

openssl req -new -key serwer.bezszyfru -out serwer.cert

OpenSSL zapyta nas o rozmaite informacje, takie jak kod ISO kraju (np. PL), miasto, nazwę organizacji lub firmy czy też nasze nazwisko. Jeżeli nie chcemy się zbytnio nad tym wszystkim rozwodzić, to możemy pozostawić wszystkie pola puste.

Kolejny krok polega na podpisaniu certyfikatu. Robi się to za pomocą komendy:

openssl x509 -req -in serwer.cert -signkey serwer.bezszyfru -out serwer.cert

Oczywiście, nie ma się co łudzić, że ktoś będzie honorował nasz podpis. Ostatecznie nie jesteśmy VeriSignem czy Thawte i przeglądarki będą wyświetlały ostrzeżenie, że nasz certyfikat jest nieważny.

Stworzone w ten sposób pliki należy skopiować do katalogu konfiguracyjnego Apache'a i tak ustawić ich prawa dostępu, aby były one odczytywalne tylko dla roota. Można to zrobić następująco:

find /etc/apache2/serwer* -type f |xargs chmod 400

Jest to szczególnie ważne, jeżeli zdecydowaliśmy się nie szyfrować naszego klucza.

Konfigurowanie serwera

Pierwszą czynnością jest tu sprawdzenie w głównym pliku konfiguracyjnym Apache'a apache2.conf (lub httpd.conf), czy moduł mod_ssl jest ładowany (jeśli nie jest wkompilowany w serwer). Jeżeli jej nie ma, musimy dodać dyrektywę Load Module, której argumentami są ssl_module i ścieżka do pliku mod_ssl.so. Należy też usunąć znak # przed dyrektywą Include httpd-ssl.conf.

Następnie trzeba wprowadzić zmiany w pliku httpd-ssl.conf. W sekcji VirtualHost należy sprawdzić, czy dyrektywa DocumentRoot jest ustawiona na miejsce, w którym chcemy hostować bezpieczne strony. Domyślnie jest to zwykły katalog WWW – najczęściej htdocs, lepiej jednak stworzyć dla nich osobne miejsce – np. /var/www/htdocs-ssl.
Linia, która zaczyna się od frazy SSLCipherSuite, jest listą dozwolonych i zabronionych standardów szyfrowania. Kolejność, w jakiej się one znajdują, wyznacza ich priorytet podczas wyboru. To, co tutaj wybierzemy, zależy już od naszej polityki bezpieczeństwa. Im większe wymagania, tym więcej użytkowników ze starymi przeglądarkami pozostawiamy „na lodzie”. Blog InfiniteSecond zaleca zastosowanie następującej polityki:

SSLCipherSuite DHE-RSA-AES256-SHA:EDH-RSA-DES-CBC3-SHA:DHE-RSA-AES128-SHA: AES256-SHA:DES-CBC3-SHA:AES128-SHA:RC4-SHA

Z innymi, słabszymi wersjami można się zapoznać na stronie infinitesecond.blogspot.com/2008/03/recommended-sslciphersuite.html.

Teraz należy przejść do linii zaczynających się od SSLCertificateFile i SSLCertificateKeyFile, jako ich argumenty podając nazwy wygenerowanych wcześniej plików (odpowiednio serwer.cert i serwer.bezszyfru).

Ostatnią czynnością jest stworzenie zestawu reguł dla katalogu zawierającego bezpieczne strony – może to być coś takiego, choć oczywiście nie jest to zbyt restrykcyjne ustawienie:


Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
allow from all


Teraz po restarcie serwera Apache (/etc/init.d/apache2 restart), jeżeli wejdziemy na naszą stronę, korzystając z protokołu https:// (a nie http://), przeglądarka poinformuje nas, że korzystamy z bezpiecznego połączenia, wyświetlając w Pasku statusu małą kłódeczkę.

Jak zablokować dostęp do strony WWW dla poszczególnych krajów? [.htaccess]

Czasem zdarza się, że chcemy, aby nasza strona internetowa była np. dostępna tylko dla internautów z Polski. Mogliśmy na przykład podpisać umowę z dostawcami treści, którzy zakazują nam udostępniania ich materiałów poza Rzeczpospolitą. Jak rozwiązać taki problem?

Dla osób korzystających z serwera Apache, pomocą okaże się odpowiednie przygotowanie pliku .htaccess. Ręcznie tego raczej jednak nie zrobimy: przygotowanie odpowiedniego ciągu zablokowanych adresów IP to niezwykle nużące zadanie. Dlatego możemy skorzystać z API geolokalizacji IP, dostarczanego przez serwis blogama.org oraz specjalnego skryptu, który wygeneruje nam plik dostępowy.

Wpierw jednak należy zrozumieć, jak działają reguły w pliku .htaccess. Jeśli ustawimy własność allow dla krajów "PL, DE" (Polska i Niemcy), dopuszczony będzie tylko ruch przychodzący z Polski i Niemiec. Jeśli ustawimy własność deny dla "US, CA", zablokowany będzie tylko ruch przychodzący ze Stanów Zjednoczonych i Kanady.

Wygenerowanie pliku .htaccess za pomocą API geolokalizacji IP jest bardzo proste – usługa dostępna jest pod adresem iplocationtools.com. Przykładowo wygenerowany plik .htaccess może wyglądać następująco:

iplocationtools.com/country_query.php?country=PL&output=htaccess_allow

gdzie parametr country określa listę kodów krajów, oddzielonych od siebie przecinkami, zaś output to typ blokowania.

W rezultacie otrzymamy plik wyglądający następująco:

#COUNTRY_BLOCK_START



order deny,allow
allow from 57.66.162.0/24
allow from 57.66.195.0/26
allow from 57.66.195.64/27
allow from 57.66.195.96/28

[…]

deny from all



#COUNTRY_BLOCK_END



Jednak bloki IP często przechodzą z rąk do rąk. Generowanie za każdym razem pliku .htaccess mogłoby się okazać niewygodne. Pomóc może nam skrypt, stworzony przez autorów mechanizmu geolokalizacji z blogama.org.

Zanim go uruchomimy, należy w katalogu roboczym z którego korzystamy stworzyć plik htaccessfile.txt, do którego wprowadzamy wszystkie ścieżki dostępowe do plików .htacces, które chcemy zmieniać. Na przykład:

/var/www/mojblog.pl/.htaccess
/var/www/mojafirma.pl/.htaccess

W samym skrypcie na początku można znaleźć parametry konfiguracyjne:

WORKDIR="/var/www/" – katalog z prawami zapisu, w którym umieszczony jest skrypt,
HTACCESSFILE="htaccessfile.txt" – plik ze ścieżkami dostępu do plików .htaccess,
HTACCESSBLOCK="htaccess-blocklist.txt" – plik roboczy,
TEMPFILE="htaccess.temp" – plik roboczy,
COUNTRIES="PL" – lista krajów,
TYPE="allow" – typ dostępu: ekskluzywny (allow) lub inkluzywny (deny).

Następnie należy nadać skryptowi prawa wykonawcze:
chmod +x nazwaskryptu.sh


i dodać go do crontabu

* * * * * /ścieżka/nazwaskryptu.sh >/dev/null 2>&1



Dzięki temu będziemy mogli regularnie aktualizować bazę zablokowanych (bądź dopuszczonych) adresów.

A oto wspomiany skrypt:
#!/bin/bash
###BLOGAMA.ORG###
###MODIFY THIS SECTION###
WORKDIR="/var/www/"
HTACCESSFILE="htaccessfile.txt"
HTACCESSBLOCK="htaccess-blocklist.txt"
TEMPFILE="htaccess.temp"
COUNTRIES="PL"
TYPE="allow"
#########################
#####DO NOT MAKE MODIFICATIONS BELOW#####
cd $WORKDIR
#Get the file from blogama.org API
wget -c --output-document=$HTACCESSBLOCK "http://blogama.org/country_query.php?country=$COUNTRIES&output=htaccess_$TYPE"
for i in $( cat $WORKDIR$HTACCESSFILE ); do
if [ -f $i ]; then
cat $i 2>&1 | grep "COUNTRY_BLOCK_START"
if [ "$?" -ne "1" ]; then #ALREADY IN HTACCESS
sed '/#COUNTRY_BLOCK_START/,/#COUNTRY_BLOCK_END/d' $i > $WORKDIR$TEMPFILE
cat $WORKDIR$HTACCESSBLOCK >> $WORKDIR$TEMPFILE
mv $WORKDIR$TEMPFILE $i
else #NOT IN HTACCESS
cat $WORKDIR$HTACCESSBLOCK >> $i
fi
fi
done
rm -f $WORKDIR$HTACCESSBLOCK

Jak sprawdzić bezpieczeństwo sieci bezprzewodowej?

narzędzi, działających w środowisku Windows, ale ich możliwości są nieco ograniczone, ze względu na ograniczenia sterowników WiFi dla systemu z Redmond). Możemy wykorzystać zarówno popularne Ubuntu, Fedorę czy OpenSUSE, jak i specjalizowane dystrybucje do audytów bezpieczeństwa, takie jak Backtrack (który ma m.in. tę zaletę, że można go uruchomić z pendrive'a, bez konieczności instalowania na dysku twardym komputera). BackTrack zawiera od razu gotowe wszystkie potrzebne narzędzia bezpieczeństwa. Jego najnowszą wersję 4 Prerelease można pobrać ze strony www.remote-exploit.org/backtrack_download.html.

Do testów wykorzystamy zaś zestaw skryptów aircrack-ng, który pozwala zarówno na monitoring ruchu sieciowego, jak i wstrzykiwanie do niego odpowiednio spreparowanych pakietów. Aircrack-ng jest dostępny zarówno na stronie projektu, jak i w repozytoriach popularnych dystrybucji. Jego instalacja sprowadza się do wydania polecenia sudo apt-get install aircrack-ng (Debian, Ubuntu) czy yum install aircrack-ng (Fedora).

Potrzebujemy też w komputerze karty sieciowej, która będzie kompatybilna z aircrackiem. Z listą obsługiwanych układów można zapoznać się na stronie www.aircrack-ng.org/doku.php?id=compatibility_drivers.

Najwygodniej jest wykorzystywać taki program terminala, który pozwala nam używać wielu sesji powłoki w kartach – będziemy bowiem jednocześnie używać wielu skryptów z pakietu aircrack-ng. Może to być np. Konsola środowiska KDE czy Terminal środowiska GNOME.
Monitoring

Pierwszym krokiem jest rozpoczęcie monitorowania ruchu sieciowego do punktu dostępowego, który będziemy testować, tak aby nie nawiązywać z nim połączenia. Zakładając, że nasza karta sieciowa nosi w systemie nazwę wlan0 (można to sprawdzić, wydając polecenie iwconfig, przedstawiające listę aktywnych interfejsów sieciowych z rozszerzeniem WiFi), uzyskujemy uprawnienia roota poleceniem su - (lub używamy sudo)a następnie wpisujemy w powłoce polecenie:

airmon-ng start wlan0

jeśli wszystko pójdzie dobrze, powinniśmy otrzymać komunikat podobny do tego, jak na poniższym zrzucie ekranu.

Teraz polecenie iwconfig powinno pokazać nam, że dysponujemy specjalnym interfejsem sieciowym mon0. Za jego pomocą będziemy monitorować ruch sieciowy. Wydajemy więc polecenie (jako root):

airodump-ng mon0

W efektcie uzyskujemy listę wszystkich punktów dostępowych w otoczeniu: ich adres MAC (BSSID), dane o sile sygnału, generowanym ruchu, przesyłanych danych, kanale na którym odbywa się transmisja, rodzaju szyfrowania i uwierzytelnienia oraz nazwie punktu (ESSID).

Poniżej wyświetlana jest lista klientów łączących się z danymi sieciami bezprzewodowymi. Gdy znajdziemy już na liście sieć, którą chcemy przetestować, zapiszmy do pliku tekstowego informacje o kanale, na którym działa oraz jej adres MAC (BSSID). Zapiszmy też informacje o wszystkich klientach (STATION) powiązanych z danym BSSID sieci. Teraz możemy przerwać już działanie airodump, wciskając kombinację klawiszy Ctrl-C.

Przechwytywanie

Teraz uruchomimy ponownie airodump-ng, tak aby zbierać pakiety dla danej sieci bezprzewodowej i zapisywać je do pliku. Jeśli nasz punkt dostępowy działa np. na kanale 11, jego BSSID to 00:00:0A:FF:01:DD, monitorujący interfejs sieciowy nazywa się mon0, a plik, do którego będziemy zapisywać pakiety to wifi_zrzut, wydajemy polecenie:

airodump-ng --channel 11 --bssid 00:00:0A:FF:01:DD --write wifi_zrzut mon0

Teraz pozostaje czekać – powinniśmy zgromadzić około 40 tysięcy pakietów, aby dostać się do klucza WEP. Może to w wypadku niezbyt aktywnych punktów dostępowych zająć wiele godzin, dlatego zmusimy router WiFi, aby wygenerował nam dodatkowe pakiety dzięki narzędziu aireplay-ng.
Wstrzykiwanie

Uruchamiamy drugą sesję terminala (w pierwszej działa airodump-ng). Listę ataków można zobaczyć po wpisaniu polecenia aireplay-ng. Standardowo wykorzystywany jest atak wykorzystujący pakiety ARP. Jeśli mamy spisany BSSID klienta, korzystającego z punktu dostępowego, tym lepiej. W przeciwnym razie możliwe, że nasze połączenie zostanie odrzucone. Ograniczymy się też do wysyłania 30 pakietów na sekundę.

Za pomocą polecenia

aireplay-ng -3 -b 00:00:0A:FF:01:DD -h FF:FF:FF:FF:FF:FF -x 30 mon0

rozpoczynamy wstrzykiwanie pakietów. Jak widać, parametr b określa adres MAC punktu dostępowego, parametr h określa MAC klienta, x odpowiada za liczbę pakietów wysyłanych na sekundę, a wlan0 to nazwa naszego interfejsu sieciowego.
Crackowanie

Po zebraniu pewnej liczby pakietów, możemy przystąpić do crackowania. W nowym terminalu spróbujemy uzyskać klucz WEP za pomocą polecenia (zakładając, że pakiety zapisujemy do pliku wifi_zrzut):

aircrack-ng wifi_zrzut*.cap

To rozpoczyna proces łamania hasła – jeśli zebraliśmy wystarczającą liczbę pakietów, powinniśmy uzyskać komunikat KEY FOUND! z komentarzem „Decrypted correctly: 100%”. Otrzymany klucz jest podany w postaci heksadecymalnej (np. 40:88:FF:A0:12) i może być wpisany jako hasło połączeniowe po usunięciu dwukropków.

Uwagi

Jeśli mamy problemy ze wstrzykiwaniem pakietów, warto sprawdzić nasz interfejs sieciowy, czy w ogóle daje taką możliwość, za pomocą polecenia aireplay-ng -9 wlan 0.

Jeśli potrzebujemy zmienić adres MAC naszego interfejsu sieciowego na np. 11:22:33:44:55:66 (ponieważ punkt dostępowy wykorzystuje filtrowanie po adresach MAC), wykorzystujemy polecenia ifconfig wlan0 down && ifconfig wlan0 hw ether 11:22:33:44:55:66 && ifconfig wlan0 up.


WPA-PSK

Atak na klucz WPA-PSK jest atakiem słownikowym, dlatego im lepszy mamy słownik, tym większe nasze szanse na pokonanie tego zabezpieczenia. Dobre słowniki znajdziecie w naszym dziale download . Pamiętajcie też, że atak jest możliwy tylko wtedy, gdy z AP połączony jest przynajmniej jeden klient.
1. Otwieramy pierwszy terminal i wpisujemy:
#ifconfig ath0 up



#airmon.sh start ath0






Karta działa teraz w trybie monitoringu.

2. Teraz zobaczymy co słychać w eterze:
#airodump ath0 x 0 1






3. Na kanale ... widzimy sieć zabezpieczoną kluczem WEP. Przyjrzyjmy się jej bliżej:
#airodump ath0 x ... 1






4. Otwieramy drugi terminal
Stosujemy atak 0 (deauthentication) na jednym z klientów połączonych z AP. Spowoduje to jego rozłączenie i ponowne połączenie z 4 etapowym procesem wymiany klucza WPA_PSK (tzw. WPA handshake - uścisk dłoni), który przechwyci airodump.
#aireplay -0 15 -a 3e:00:20:xx:xx:xx -c 10:00:1e:yy:yy:yy ath0






5. Otwieramy trzeci terminal i włączamy aircracka w celu sprawdzenia, czy airodump przechwycil WPA-handshake.
#aircrack -w /katalog_ze_slownikiem/slownik.txt







Jeżeli przy danej sieci zobaczymy przechwycony WPA-handshake, wtedy wybieramy ją i rozpoczyna się proces łamania klucza WPA-PSK.



Możemy wtedy zamkąć pierwszy i drugi terminal. Jeżeli klucz WPA był w słowniku, to po pewnym czasie nasz atak zakończy się sukcesem:


UWAGA!: PAKIET AIRCRACK DZIAŁA W PEŁNI TYLKO Z ODPOWIEDNIMI KARTAMI WLAN, JAKĄ KARTĘ KUPIĆ DOWIESZ SIĘ W DZIALE SPRZĘT!


To już wszystko, co chciałem Wam przekazać na temat AIRCRACKA, mam nadzieję, że zdobyte wiadomości wykorzystacie jedynie w celu rozwinięcia swojej wiedzy, nie łamiąc przy tym prawa!


Jak przyśpieszyć zapytania do bazy MySQL?

Oto garść porad, których zastosowanie powinno przyśpieszyć działanie twoich skryptów i odciążyć serwer baz danych. Większość z nich znajdzie zastosowanie ogólnie przy relacyjnych bazach danych, nie tylko przy MySQL-u.

Korzystaj z typu CHAR gdy tylko to jest możliwe (zamiast VARCHAR, BLOB czy TEXT). Wiele kolumn na pewno będzie zawierało pola o stałej długości – np. polski numer IBAN to zawsze 26 znaków. Dane z kolumn typu CHAR mogą być znacznie szybciej przeszukane, niż z kolumn innych typów.

Zaoszczędź na pamięci wykorzystywanej na każdą kolumnę, deklarując jej rozmiar na tyle tylko, aby wystarczyło na zachowanie przechowywanych wartości.

Jeśli kolumna nie jest pusta, zadeklaruj to za pomocą NOT NULL. To przyśpieszy przeszukiwanie tabeli.

Nie dziel tabeli, jeśli wydaje ci się, że masz zbyt wiele kolumn. Podczas uzyskiwania dostępu do wiersza, najwięcej czasu zajmuje wyszukanie pierwszego bajtu w wierszu.

Jeśli przeszukujesz wiersze w tej samej kolejności (np. wyr1, wyr2, wyr3, …), zoptymalizuj tabelę za pomocą polecenia ALTER TABLE … ORDER BY wyr1, wyr2, wyr3.

Nie używaj pętli PHP aby pobrać z bazy dany wiersze jeden po drugim. Zamiast tego lepiej skorzystać z dyrektywy IN, np. tak: SELECT * FROM 'tabela' WHERE 'id' IN (1,3,5,9,11);

Nie trzymaj w bazie plików binarnych (np. obrazków) – najlepiej by były one zachowane na dysku jako pliki, a w bazie znajdowały się tylko odnośniki do nich.

Jeśli musisz w bazie trzymać pliki tekstowe o dużych rozmiarach, sprawdź, czy nie lepiej zadeklarować typu kolumny jako BLOB, wprowadzać dane po ich skompresowaniu gzipem, a następnie dekompresować już w aplikacji.

Jeśli ładujesz tabelę z pliku tekstowego, wykorzystaj polecenie LOAD DATA INFILE. Jest bardzo szybkie.

Dane o sesji użytkownika, jak i wszelkie inne niekrytyczne dane, warto trzymać w tabeli MEMORY. Jest o wiele szybsza niż inne. Tabelę taką zakłada się poleceniem CREATE TABLE test ENGINE=MEMORY;.

Porzuć REPLACE. REPLACE to złożenie DELETE i INSERT. Lepiej jest użyć INSERT … ON DUPLICATE KEY UPDATE (czyli INSERT oraz UPDATE, jeśli doszło do konfliktu).

Unikaj stosowania klauzuli HAVING. Jest dość powolna.

Grupuj podobne INSERT-y w jeden długi INSERT z wieloma wartościami, tak aby wstawić wiele wierszy jednocześnie. Każde połączenie, przesłanie i parsowanie kwerendy zajmuje kilkukrotnie dłużej niż samo wstawienie danych. Jeśli takie zgrupowanie jest niemożliwe, to jeśli korzystasz z engine'u InnoDB, wypróbuj START TRANSACTION oraz COMMIT. Jeśli jest to MyISAM, zastosuj LOCK TABLES – wówczas bufor indeksu będzie napełniany tylko raz, po wszystkich INSERT-ach. (Pamiętaj jednak, żeby co kilkaset wierszy otwierać (unlock) tabele, aby inne wątki miały do nich dostęp).

Korzystaj z funkcji BENCHMARK, aby przetestować poszególne wyrażenia.


Wyłączenie konta root

Takie ustawienie jest akurat domyślne w Ubuntu. Użytkownicy innych dystrybucji powinni sprawdzić, czy mają dostęp do sudo za pomocą komendy visudo. Służy ona bezpiecznej edycji pliku sudoers. Następnie należy dodać do niej linijkę nazwauzytkownika ALL=(ALL) ALL.

Następnie można zablokować konto roota za pomocą komendy sudo passwd -l root.
Zablokowanie dostępu do SSH

Należy to zrobić blokując logowanie dla roota, wyłączając uwierzytelnianie przez hasła i ustawiając odpowiednie wpisy w pliku denyhost.

Aby wyłączyć logowanie roota, należy w pliku /etc/ssh/ssd_config znaleźć linię PermitRootLogin yes i zmienić ją na PermitRootLogin no.

Aby wyłączyć uwierzytelnianie przez hasło (stosowane wówczas będą tylko klucze publiczne), należy we wspomnianym wyżej pliku zmienić linię #PasswordAuthentication yes na PasswordAuthentication no.

Denyhosts wymaga dodatkowej instalacji – najprościej zrobić to za pomocą komendy sudo apt-get install denyhosts. Ustawienia aplikacji można znaleźć w /etc/denyhosts.conf.
Aktualizacja systemu: cron-apt

Pamiętanie o samodzielnej, regularnej aktualizacji systemu może być problematyczne. Jeśli lista naszych repozytoriów wskazuje tylko na te, które związane są z poprawkami bezpieczeństwa, warto zautomatyzować ten proces. W Debianie i Ubuntu można w tym celu wykorzystać cron-apt. Instaluje się go poleceniem sudo apt-get install cron-apt. Potem należy tylko ustawić swój adres e-mailowy w pliku /etc/cron-apt/config, pole MAILTO=. Według standardowych ustawień cron-apt będzie aktualizował system codziennie, o 4 nad ranem. Można to zmienić w pliku /etc/cron.d/cron-apt.
Restrykcyjna konfiguracja zapory sieciowej (firewalla)

Zestawiając reguły zapory sieciowej, pozwól tylko na takie połączenia, jakie naprawdę są potrzebne. IPtables to potężne narzędzie, a w Sieci dostępnych jest wiele gotowych, dobrze działających konfiguracji. Przykładowo reguły dla maszyny, która działać ma tylko jako serwer WWW, zarządzany przez SSH, mogłyby wyglądać następująco
iptables -A OUTPUT -o eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp -i eth0 --dport 22 --sport 1024:65535 -m state --state NEW -j ACCEPT
iptables -A INPUT -p tcp -i eth0 --dport 80 --sport 1024:65535 -m state --state NEW -j ACCEPT



Zakładając oczywiście, że eth0 to nasz interfejs sieciowy, a połączenia HTTP i SSH odbywają się odpowiednio na portach 80 i 22.

Samodzielne pisanie reguł dla IPtables nie jest proste, ale pomóc w tym może wiele wygodnych do tego narzędzi. Spośród nich warto polecić takie aplikacje jak shorewall i firewall builder.
Zabezpieczenie PHP za pomocą Suhosin

Suhosin to system ochronny dla PHP, który pozwala na zabezpieczenie serwerów i użytkowników przed konsekwencjami znanych i nieznanych błędów w rdzeniu PHP. Prowadzi on czasem do problemów z kompatybilnością źle napisanych skryptów. Najprościej zainstalować go pisząc sudo apt-get install php5-suhosin. Następnie należy w pliku /etc/php5/conf.d/suhosin.ini wpisać linię extension=suhosin.so.
Zabezpieczenie bazy danych MySQL

Niezłym pomysłem na zabezpieczenie serwera baz danych przed włamaniem jest zablokowanie logowania jako root z LAMP-owego serwera, tak aby np. można było to zrobić tylko z poziomu laptopa administratora. Polecenie mysql update user set host = 'x.x.x.x' where user="root" (gdzie x.x.x.x oznacza adres IP komputera, z którego można się będzie logować), uniemożliwi osobom, które miałyby konto z prawami roota, zalogowanie się do bazy danych.

Konfiguracja Apachea

Domyślny plik konfiguracyjny serwera jest bardzo rozbudowany i warto z niego zrezygnować, tworząc jednocześnie od podstaw swój własny zbiór z ustawieniami. Z racji tego, że jest to dość trudne, warto posłużyć się tutaj gotowymi wpisami z oryginalnego pliku.

W tym miejscu skupimy się na kwestiach najbardziej istotnych, czyli parametrach, które mają wpływ na bezpieczeństwo systemu. Pierwszą opcją, o której już zresztą wspomnieliśmy, jest konto użytkownika, na którym działa serwer. Zakładamy więc, że opcje User i Group zostały już poprawnie ustawione.

Ograniczenie dostępu do konfiguracji serwera można wymusić przez zablokowanie użycia plików .htaccess. Pisaliśmy o tym wcześniej w artykule „Jak używać plików .htaccess”. Przypomnijmy tylko w skrócie, że jeżeli nie chcemy, aby użytkownicy mogli samodzielnie zmieniać niektóre parametry pracy Apache’a, to w wybranej sekcji ustawiamy wartość dyrektywy AllowOverride na None. Warto to zrobić na poziomie struktury całego dysku, zamieszczając odpowiedni wpis w sekcji root:

AllowOverride None


Zabieg ten sprawi, że użycie .htaccess nie będzie możliwe, o ile dla innego katalogu nie zostanie to jawnie wskazane. Wspomnianą wcześniej dyrektywę warto rozszerzyć o dodatkowe wpisy limitujące dostęp do serwera:

Order Deny,Allow
Deny from All
AllowOverride None


W ten sposób zablokowaliśmy dostęp do serwera na poziomie wszystkich zasobów. W pozostałych sekcjach Directory należy go oczywiście odblokować, tak by dana strona była dostępna dla wszystkich lub tylko wybranych adresów IP. Dokładniejsze wyjaśnienie tego zagadnienia jest zawarte w rozdziale „Blokowanie dostępu do strony” wspomnianego już artykułu o .htaccess. Warto tylko przypomnieć ogólną zasadę tworzenia polityki dostępu: najpierw blokujemy wszystkie komputery, a dopiero później jawnie przyznajemy dostęp wybranym komputerom (osobom) lub ich grupie.

Gdy zdecydujemy się przyznać użytkownikom możliwość tworzenia plików .htaccess, powinniśmy zadbać o to, aby nikt postronny nie miał do nich dostępu. Inaczej mówiąc, należy zablokować pobieranie tego typu plików z serwera. Służy do tego dyrektywa Files:

Order allow,deny


Uwaga: dyrektywa ta zapewne jest już zapisana w domyślnej konfiguracji serwera. Warto zatem zamieścić tam tylko dodatkową regułę, ograniczającą dostęp do plików .inc, które są używane w skryptach:

Order allow,deny


HTTP pod kontrolą, czyli mod_security

Wszystkie omówione do tej pory mechanizmy związane były z zapewnieniem bezpieczeństwa na poziomie serwera WWW lub systemu, w którym jest on uruchomiony. Prawdziwe pole do popisu dla sieciowych włamywaczy stanowią jednak aplikacje internetowe. Przyczyn jest wiele, a do najważniejszych należą błędy w implementacjach usług i języków, niewłaściwa konfiguracja serwera i jego rozszerzeń, a przede wszystkim źle napisany kod. W artykule „Siedem najgroźniejszych ataków na serwisy WWW" omówiliśmy najczęściej wykorzystywane luki w aplikacjach WWW oraz sposoby radzenia sobie z nimi. Błędów i pomyłek w kodzie nie da się jednak uniknąć, dlatego do ochrony programów sieciowych warto podejść także z drugiej strony.

reklama


Firewall najwyższego poziomu

Większość typowych zapór ogniowych pracuje na poziomie protokołu TCP/IP. Przy ich użyciu możemy skutecznie odfiltrować wybrane hosty i porty. W wypadku aplikacji sieciowych taka analiza nie wystarcza, bo ataki mogą być przeprowadzane poprzez protokół HTTP. Wystarczą źle napisana strona WWW i umiejętnie spreparowane zapytanie, by skasować lokalną bazę danych, pobrać z niej tajne dane (np. numery kart kredytowych) czy po prostu wykonać jakiś program na serwerze. Do ochrony przed tego typu zagrożeniami niezbędne są zatem analizowanie ruchu po protokole HTTP, wykrywanie danych przychodzących w zapytaniach i blokowanie tych, które potencjalnie stanowią zagrożenie.

Osłonę taką stanowią programy nazywane firewallami aplikacji sieciowych (ang. web application firewall lub application layer firewall). Tego typu narzędzia analizują ruch po protokołach siódmej warstwy modelu OSI, czyli warstwy aplikacji (tu: protokołu HTTP). Na podstawie analizy przesyłanych danych zapory mogą monitorować, logować czy po prostu blokować ruch sieciowy.

Znakomitym firewallem aplikacyjnym dla serwera WWW jest ModSecurity. Program ten działa jako moduł serwera, w pełni integrując się z Apache’em (może zostać skompilowany wewnątrz serwera lub jako moduł dynamicznie ładowany na żądanie). ModSecurity analizuje zarówno ruch przychodzący, jak i wychodzący. W pierwszym wypadku jest w stanie wykryć nieuprawnione zapytania w metodach GET, POST i ciasteczkach. Działanie ModSecurity opiera się na zdefiniowanych przez administratora zestawach reguł wraz z przypisanymi im akcjami. Baza reguł (sygnatur) stanowi podstawę do wnioskowania na temat zagrożeń – niebezpiecznych ciągów znaków przekazywanych w sesjach HTTP, które powinny zostać zablokowane, zarejestrowane itd.

Instalacja ModSecurity

ModSecurity kompilujemy ze źródeł (do pobrania ze strony ModSecurity) lub instalujemy z gotowej paczki binarnej. Pakiety binarne są przygotowywane przez niezależnych autorów. Ze względów licencyjnych wiele dystrybucji zrezygnowało z dostarczania ModSecurity we własnych systemach. Odnośniki do paczek przeznaczonych dla kilku najpopularniejszych odmian Linuksa znajdziemy na stronie ModSecurity Download. Na przykład pakiety dla Debiana przygotowuje Alberto Gonzalez Iniesta i są one dostępne na stronie http://etc.inittab.org/~agi/debian/libapache-mod-security2/. Możemy pobrać je samodzielnie i zainstalować w systemie lub skorzystać z repozytorium APT. W drugim wypadku do pliku /etc/apt/sources.list dopisujemy wiersz:
deb http://etc.inittab.org/~agi/debian/libapache-mod-security2/etch ./

Na koniec poleceniem apt-get update odświeżamy listę pakietów gotowych, po czym możemy przystąpić do właściwej instalacji ModSecurity. Kolejne komendy wyglądają tak:
apt-get install mod-security2-common libpapache2-mod-security2
a2enmod mod-security
/etc/init.d/apache2 force-reload

Pierwsze polecenie zainstalowało wszystkie wymagane pakiety. Druga komenda, specyficzna dla Debiana, uaktywniła moduł ModSecurity w Apache’u, trzecia natomiast spowodowała jego ponowne uruchomienie. W zależności od dystrybucji składnia tych poleceń może być różna, a w szczególności inny może być sposób włączenia ModSecurity do konfiguracji Apache’a. W większości przypadków w pliku ustawień serwera wystarczy dopisać wiersze:
LoadFile /usr/lib/libxml2.so.2
LoadModule security_module /usr/lib/apache2/modules/mod_security2.so

Teraz możemy przystąpić do konfiguracji ModSecurity. Ustawienia modułu zamieszczamy wewnątrz dyrektywy . Szybkie rozpoczęcie pracy z serwerem jest możliwe dzięki obecności w katalogu /usr/share/doc/mod-security2-common/examples proponowanych plików ustawień dla Apache’a zarówno w wersji podstawowej (-minimal), jak i rozbudowanej (podkatalog rules). W pierwszym wypadku wystarczy przekopiować zawartość wybranej konfiguracji do pliku ustawień serwera (httpd.conf lub apache2.conf), a następnie ponownie uruchomić Apache’a. Domyślna konfiguracja ModSecurity (wersja rozbudowana) pozwala w dość szybki sposób zabezpieczyć serwer WWW przed podstawowymi typami ataków SQL Injection, Path Traversal czy XSS. Dlatego warto podjąć wysiłki, aby ją wdrożyć w naszym serwerze. W pliku konfiguracyjnym Apache’a dopisujemy wiersz:
Include conf/modsecurity/*.conf

a następnie kopiujemy zawartość podkatalogu rules do katalogu /etc/apache2/conf/modsecurity. Równie dobrze możemy jednak użyć innych ścieżek do plików z sygnaturami, jak zostanie to pokazane w dalszej części artykułu.

ModSecurity z paczki

W Sieci znajdziemy wiele innych rozbudowanych zestawów reguł, gotowych do użycia wraz z ModSecurity. Wystarczy w Google'u wpisać wyrażenie mod_security rules, by otrzymać kilka interesujących wyników. Bez wątpienia do najlepszych należą paczki udostępnione w serwisie Got Root?. Obejmują one reguły chroniące przed atakami, o których wspomnieliśmy wcześniej, ale także zawierają dodatkowe sygnatury bezpieczeństwa, specyficzne dla konkretnych serwisów WWW/PHP, takich jak fora internetowe czy systemy CMS. Reguły Got Root? potrafią także zablokować znane rootkity, robaki internetowe oraz „niepożądane” przeglądarki-roboty (UserAgents).

reklama


Sygnatury, o których mowa, są dostępne na stronie http://www.gotroot.com/tiki-index.php?page=mod_security+rules. Można pobrać paczki przeznaczone dla serwera Apache w wersjach 1.x i 2.x oraz modułu ModSecurity 1.9 oraz 2.x.

Procedura instalacji sygnatur jest bardzo prosta. Najpierw trzeba już mieć właściwy moduł ModSecurity skonfigurowany do współpracy z Apache'em. W pliku ustawień serwera WWW sprawdzamy, czy istnieje dyrektywa włączająca zewnętrzne pliki konfiguracyjne z katalogu /etc/apache2/conf.d. Jeżeli nie, dopisujemy w nim następujący wiersz:
Include conf.d/*.conf

Teraz w katalogu /etc/apache2/conf.d tworzymy plik mod_security.conf, w którym zamieszczamy podstawową konfigurację ModSecurity. My posłużymy się tą dostarczoną przez serwis Got Root? i opatrzymy własnymi komentarzami. Oczywiście w tym miejscu równie dobrze możemy użyć dowolnej innej konfiguracji lub po prostu napisać własną od podstaw:


SecFilterEngine On
# Włącza działanie mechanizmu filtrującego.

SecFilterDefaultAction "deny,log,status:500"
# Domyślna akcja podejmowana w przypadku wykrycia nieuprawnionych
zapytań. Tutaj jest to blokowanie (deny), rejestrowanie zdarzenia
(log) oraz zwrócenie komunikatu - statusu serwera o numerze 500
(Internal Server Error).

SecFilterScanPOST On
SecFilterCheckURLEncoding On
SecFilterCheckCookieFormat On
SecFilterCheckUnicodeEncoding Off
SecFilterNormalizeCookies On
SecFilterCookieFormat 1
# Włącza filtrowanie zapytań POST. Kilka domyślnych ustawień
związanych ze sprawdzaniem poprawności adresów URL,
kodowaniem UNICODE itp.

SecServerResponseToken Off

SecFilterScanOutput On
SecFilterOutputMimeTypes "(null) text/html text/plain"
# Filtrowanie danych wychodzących z serwera.

SecFilterForceByteRange 1 255
# Dopuszcza bajty o wartości z zakresu 1-255.

SecServerSignature "Prywatny serwer"
# Ukrywanie nazwy serwera. Apache będzie się przedstawiał
jako "Prywatny serwer".

SecAuditEngine RelevantOnly
SecAuditLog logs/audit_log
# Logowanie naruszeń polityki bezpieczeństwa. Wskazanie pliku
z logami.

SecFilterDebugLevel 0
SecFilterDebugLog logs/modsec_debug_log
# Opcje debugowania - wyłączone. Wskazanie pliku z logami
z operacji debugowania.

Include /etc/modsecurity/exclude.conf
# Dołącza reguły - wyjątki filtrowania. Reguły te muszą występować
przed pozostałymi.

Include /etc/modsecurity/rules.conf
# Dołącza reguły związane z ochroną aplikacji internetowych.

Include /etc/modsecurity/blacklist.conf
# Dołącza reguły związane z ochroną przed spamem w formularzach.

Include /etc/modsecurity/blacklist2.conf
# Dołącza reguły związane z blokowaniem niepożądanych komputerów
i serwerów proxy.

Include /etc/modsecurity/useragents.conf
# Dołącza reguły związane z blokowaniem niepożądanych klientów,
przeglądarek-robotów itd.

Include /etc/modsecurity/rootkits.conf
# Dołącza reguły związane z ochroną przed rootkitami, malware'em
i innym szkodliwym oprogramowaniem.

Include /etc/modsecurity/proxy.conf
# Dołącza reguły dotyczące blokowania prób używania serwera
jako proxy.

Include /etc/modsecurity/apache2-rules.conf
# Dołącza dodatkowe reguły specyficzne dla serwera Apache
w wersji 2.X.


Ostatnie osiem parametrów konfiguracyjnych z tego listingu stanowi dyrektywa Include. Włącza ona dodatkowe reguły ModSecurity z zewnętrznych plików konfiguracyjnych. Sygnatury Got Root? dystrybuowane są w postaci kilku plików. Należy je rozpakować do katalogu /etc/modsecurity/, a później właśnie dyrektywą Include jawnie włączyć do konfiguracji Apache’a. Po każdej zmianie w ustawieniach serwera pamiętajmy o jego ponownym uruchomieniu.

Dyrektywy ModSecurity

Zestaw reguł ModSecurity opiera się na kilkudziesięciu predefiniowanych dyrektywach. Pełną ich listę znajdziemy w dokumentacji umieszczonej na stronie http://www.modsecurity.org/documentation/index.html. Trzeba tu podkreślić, że między edycjami 1.x a 2.x zaszły znaczące zmiany w nazewnictwie i strukturze dyrektyw. I tak przykładowo: dyrektywa SecFilter została zastąpiona bardziej elastyczną dyrektywą SecRule. Należy o tym pamiętać, zaglądając do przykładowych plików konfiguracyjnych.

reklama


Dostępny na wymienionej wyżej stronie ModSecurity Reference Manual jest pierwszym dokumentem, od którego rozpoczynamy zapoznawanie się z dyrektywami. Każda z nich została opatrzona opisem, informacjami o składni i zakresie użycia, a także przykładami. Nie sposób omówić ich wszystkich w tym artykule. W uproszczeniu można natomiast założyć, że część ogólnych dyrektyw przyjmuje wartości z ustalonego zakresu parametrów lub jest jedynie włączona/wyłączona. Po takie informacje należy sięgnąć właśnie do podręcznika ModSecurity.

Dyrektywą wartą odnotowania w tym miejscu jest natomiast SecRule, stosowana do analizy danych, do której administrator może przypisać akcję podejmowaną na podstawie wyników tejże analizy. Składnia SecRule jest następująca:
SecRule ZMIENNA OPERATOR [AKCJA]

Parametr AKCJA jest opcjonalny – jeżeli go nie ma, podejmowane jest działanie domyślne, zapisane w konfiguracji modułu dyrektywą SecFilterDefaultAction. W dalszej części artykułu omówimy kilka innych akcji (lista dostępnych składa się z kilkudziesięciu pozycji). I tu ponownie odsyłamy do podręcznika ModSecurity, aby się z nimi zapoznać. Do najczęściej stosowanych bez wątpienia należą:
deny – zablokuj zapytanie,
allow – pozwól na wykonanie zapytania,
status:xxx – zwróć status serwera o numerze, gdzie xxx jest kodem statusu serwera,
redirect:url – przekieruj do adresu url,
log – zapisz zapytanie do pliku dziennika,
nolog – nie rejestruj zapytania w dzienniku.

W jednej regule można zadać wiele akcji, np. zablokuj i zaloguj, oddzielonych od siebie przecinkiem. OPERATOR stanowi ciąg znaków lub wyrażenie regularne. Dopasowanie zapytania do operatora powoduje, że dana reguła jest prawdziwa i należy zastosować przypisaną do niej akcję lub akcję domyślną. ZMIENNA określa „miejsce”, w którym dana reguła ma być sprawdzana. Najczęściej stosowaną zmienną jest REQUEST_URI, która nakazuje sprawdzanie reguł w adresie, a raczej parametrach zapytania przekazywanych do serwera.

Przykładem użycia może być zablokowanie próby odczytania plików shadow i passwd zawierających hasła w systemach Unix:
SecRule REQUEST_URI "/etc/shadow"
SecRule REQUEST_URI "/etc/passwd"

W podobny sposób uniemożliwimy wykonanie niektórych programów:
SecRule REQUEST_URI "/bin/bash"
SecRule REQUEST_URI "/bin/chmod"

Bardziej złożona reguła uchroni nas przed atakami typu SQL Injection zarówno w przypadku zapytań przekazywanych przez adres (REQUEST_URI), jak i w ciele wywołania (REQUEST_BODY). Wychwytywane przez nią zapytania zawierające słowa kluczowe SQL-a (jak DELETE, DROP itd.) są przez nią blokowane:
SecRule REQUEST_URI|REQUEST_BODY "((select|grant|delete|insert|
drop|alter|replace|truncate|update|create|rename|describe)
[[:space:]]+[A-Z|a-z|0-9|\*| |\,]+[[:space:]]
+(from|into|table|database|index|view)
[[:space:]]+[A-Z|a-z|0-9|\*| |\,]|
UNION SELECT.*\'.*\'.*,[0-9].*INTO.*FROM)"

I na deser reguła mogąca nas uchronić przed atakami typu Path Traversal, czyli wędrowaniu po katalogach na dysku:
SecRule REQUEST_URI "\.\./"

Przedstawione powyżej przykłady stanowią jedynie wierzchołek góry lodowej. Zachęcamy do samodzielnego przestudiowania domyślnych reguł dostarczanych standardowo wraz z ModSecurity lub z zewnętrznych źródeł.

Gadatliwy Apache

Informacja o tym, z którą wersją serwera WWW mamy do czynienia oraz jakie dodatki są na nim zainstalowano, może być punktem zaczepienia dla atakującego. Tym bardziej że potrzeba zaledwie kilku prostych czynności, aby to sprawdzić. W tym celu wystarczy udać się na stronę główną serwisu. Komunikat „It works!” nie daje złudzeń: na tym komputerze pracuje Apache. Idąc dalej tym tropem: w przeglądarce wpisujemy adres wymyślonej, nieistniejącej podstrony. Wraz z informacją o komunikacie błędu (404 – Nie znaleziono) w stopce wygenerowanego dokumentu znajdziemy pełne informacje o wersji Apache’a, systemie, na którym go zainstalowano, oraz dodatkowych modułach dołączonych do serwera – także z dokładnym numerem wersji.

Te same informacje uzyskamy, łącząc się telnetem na port 80 i wydając dowolną komendę HTTP, np. HEAD:
telnet adres_serwera 80
HEAD / HTTP/1.0

Aby wykonać komendę HTTP, należy następnie dwukrotnie nacisnąć klawisz [Enter].

W łatwy sposób możemy wyeliminować ilość informacji udostępnianych na zewnątrz przez Apache’a. Odpowiada za to dyrektywa ServerTokens, która przyjmuje jedną z sześciu wartości: Full, OS, Minor, Minimal, Major oraz Prod. Domyślnie przypisano jej wartość Full, co oznacza, że serwer jest najbardziej „gadatliwy”. Aby zwiększyć bezpieczeństwo systemu, ustalamy zatem poziom tej opcji na możliwie najniższy:
ServerTokens Prod

Dodatkowo powinniśmy przypisać dyrektywie ServerSignature wartość Off (wyłączona). W ten sposób ograniczymy podawanie informacji przez serwer podczas listowania katalogów FTP, generowania wewnętrznych stron błędów dokumentów itp.
ServerSignature Off

Dyrektywy ServerTokens i ServerSignature pozwalają ograniczyć liczbę przekazywanych na zewnątrz informacji o serwerze.

Należy natomiast pamiętać, że obie dyrektywy nie zablokują definitywnie wyświetlania przez serwer danych o nim samym. W najprostszej postaci odwiedzający serwis otrzyma informacje o tym, że na komputerze zainstalowano Apache’a. Jeżeli chcemy to ominąć, pozostaje nam zmiana w źródłach serwera i jego rekompilacja. Dane o wydaniu Apache’a przechowywane są w pliku include/ap_release.h. Najbardziej istotną definicją jest AP_SERVER_BASEPRODUCT, gdzie potencjalnie możemy zastąpić słowo „Apache” czymś innym, np. „Microsoft IIS”. Numery wersji przechowywane są w symbolach AP_SERVER_MAJORVERSION_NUMBER, AP_SERVER_MINORVERSION_NUMBER i AP_SERVER_PATCHLEVEL_NUMBER. Ale uwaga: zmiana wersji może pociągać za sobą problemy z kompilacją innych modułów serwera.

Sposób, w jaki serwer przedstawia się na zewnątrz, zmienimy także za pomocą modułu mod_security. Brak identyfikacji Apache’a wiąże się także z koniecznością usunięcia domyślnych stron startowych oraz komunikatów błędów. Kasujemy zatem katalog /var/www/apache2-default oraz ustawiamy własne komunikaty błędów. Tutaj ponownie odwołamy się do artykułu „Jak używać plików .htacces”, gdzie szerzej omówiliśmy to zagadnienie. Przypomnijmy jedynie, że wpisy allow i deny możemy stosować na poziomie konfiguracji całego serwera, poszczególnych katalogów (dyrektywa ), serwerów wirtualnych (dyrektywa ) oraz zamieszczać je w pliku .htaccess. Warto też pamiętać, że wielu włamywaczy stosuje inne techniki uzyskania informacji o zainstalowanych produktach, jak chociażby HTTP Fingerprinting.

Moduły absolutnie niezbędne do pracy z Apache’em jako serwerem WWW to core, http_core oraz jedna wybrana implementacja MPM (prefork, worker itd.). Wszystkie pozostałe możemy wyłączyć, choć tak przygotowany serwer będzie tylko w niewielkim stopniu użyteczny. Apache powinien zostać skompilowany z modułem mod_so, jeżeli pozostałe moduły chcemy ładować dynamicznie.

Z punktu widzenia bezpieczeństwa Apache’a należy skompilować moduły mod_access (kontrola dostępu do serwera), mod_auth (mechanizmy autoryzacji użytkowników) oraz mod_log_config (mechanizmy logowania zdarzeń serwera). W odniesieniu do funkcjonalności serwera warto natomiast dołączyć do niego moduły mod_dir (obsługa stron startowych), mod_mime (obsługa MIME) czy mod_userdir (strony domowe użytkowników). W Apache’u możemy zrezygnować, o ile nie zamierzamy stosować tych funkcjonalności, z mod_cgi (obsługa skryptów CGI), mod_include (funkcja Server Side Includes) czy mod_status (monitorowanie stanu serwera).

Logi, logi, logi

Dane o zdarzeniach serwera przechowywane są w pliku access.log, natomiast te o błędach samego serwera w pliku error.log. Ścieżkę do pierwszego z nich wskazuje dyrektywa CustomLog, do drugiego – Error.log. Obie dyrektywy mogą zostać zapisane w konfiguracji głównej serwera lub w ustawieniach poszczególnych serwerów wirtualnych.

O tym, które informacje o zdarzeniach są rejestrowane, a które pomijane, decyduje natomiast dyrektywa LogLevel. Określa ona poziom ważności zapisywanych zdarzeń, przyjmując jedną z wartości: debug, info, notice, warn, error, crit, alert oraz emerg. Lista ta uporządkowana jest w kolejności malejącej: w trybie debug w dzienniku zdarzeń pojawia się najwięcej wpisów, włącznie z tymi służącymi do rozwiązywania problemów przez rozwijających serwer. Z kolei ustawienie poziomu emerg skutkuje tym, że do dziennika zapisywane są tylko informacje o krytycznych, najpoważniejszych błędach serwera.

W kontekście wpisów rejestrowanych w logach należy zwrócić uwagę na dyrektywę LogFormat. Pisaliśmy o niej szerzej w artykule „Witryna pod lupą, czyli jak korzystać z webalizera”. Domyślny plik konfiguracyjny Apache’a zawiera cztery definicje formatów zapisu logów: combined, common, referer oraz agent. Ten, który chcemy zastosować, wskazujemy we wspomnianej dyrektywie CustomLog:
CustomLog logs/access_log combined

Ptaszek na uwięzi, czyli chroot

Dość powszechnie stosowaną techniką zwiększającą bezpieczeństwo serwerów internetowych jest mechanizm chroot. Jego zastosowanie polega na wydzieleniu nowej struktury plików i katalogów systemu, w obrębie których działa uruchomiony serwer. W ten sposób atakujący ma ograniczone pole manewru. Włamanie utrudnia niejednokrotnie brak powłoki (w wydzielonej strukturze nie musi ona wcale istnieć), a gdy się to natomiast uda, cracker uzyskuje dostęp jedynie do plików wykonywalnych, ustawień i logów samego serwera.

Przygotowanie chroota rozpoczniemy już na etapie instalacji Apache’a. Wystarczy wówczas uruchomić skrypt configure ze zdefiniowanymi odpowiednio ścieżkami do plików konfiguracyjnych, wykonywalnych i bibliotek oraz logów. Drugi sposób zaprezentujemy poniżej: przeniesienie istniejącej instalacji serwera do przestrzeni chroot.

Na początek zatrzymujemy uruchomioną instancję Apache’a. Tworzymy nowego użytkownika (o ile nie zostało to wcześniej zrobione), a następnie przygotowujemy strukturę nowego serwera. W tym celu wydajemy kolejno polecenia:
mkdir -p /chroot/apache
# mkdir -p /chroot/apache/dev
# mkdir -p /chroot/apache/etc/apache2
# mkdir -p /chroot/apache/lib
# mkdir -p /chroot/apache/usr/sbin
# mkdir -p /chroot/apache/var/run
# mkdir -p /chroot/apache/var/lock
# mkdir -p /chroot/apache/var/log/apache
# mkdir -p /chroot/apache/var/www/

Możliwość zapisu i wykonywania do katalogu /chroot/apache/var/log/apache powinien mieć tylko administrator:
# chmod 750 /chroot/apache/var/log/apache

W następnym kroku sprawdzamy, z jakich bibliotek korzysta Apache:
ldd /usr/sbin/apache2

Teraz należy wykonać najbardziej pracochłonny etap „zamykania” Apache’a w chroot. W tym celu kopiujemy wszystkie pliki serwera, pliki konfiguracyjne, biblioteki oraz dowiązania symboliczne do nich. Należy przy tym zachować dokładne położenie wszystkich obiektów w strukturze katalogów – może się więc okazać, że musimy utworzyć kolejny podzbiór. Nie podamy tutaj konkretnych poleceń, gdyż położenie plików różni się w zależności od używanego oprogramowania i dystrybucji Linuksa. Bardzo ogólny przepis składa się z kilku kroków:
skopiowanie katalogu /etc/apache2 do /chroot/apache/etc/apache2,
skopiowanie stron domowych, skryptów CGI z /var/www do /chroot/apache/var/www,
skopiowanie plików wykonywalnych /usr/sbin/apache2 i /usr/sbin/apache2ctl do /chroot/apache/usr/sbin.

W kolejnym kroku przygotowujemy plik urządzenia /dev/null, nadając mu jednocześnie odpowiednie parametry i prawa:
# mknod /chroot/apache/dev/null c 1 3
# chmod 666 /chroot/apache/dev/null

Teraz musimy jeszcze skopiować pliki systemowe /etc/passwd, /etc/group oraz /etc/shadow oraz usunąć z nich wszystkie wiersze poza tym definiującym użytkownika apache:
apache:x:1001:1001::/dev/null:/bin/false

Nie zapomnijmy także o skopiowaniu zbiorów /etc/hosts i /etc/nsswitch.conf, a po wykonaniu tego możemy przystąpić do pierwszego uruchomienia serwera. W tym celu wydajemy polecenie:
/usr/sbin/chroot /chroot/apache /usr/sbin/apache2

Pierwszy człon wskazuje ścieżkę do polecenia chroot. Drugi stanowi katalog, w którym chcemy zamknąć Apache’a, czyli tu /chroot/apache, ostatni natomiast określa ścieżkę do pliku wykonywalnego serwera. Zauważmy, że każdy z nich oddzielony jest spacją!

Upewnijmy się jeszcze, czy Apache został „uwięziony” w chroocie. Poleceniem ps –A | grep apache2 listujemy wszystkie procesy serwera, po czym zapisujemy numer (PID) dowolnego z nich. Następnie za pomocą komendy ls /proc/numer_procesu/root sprawdzamy, w którym drzewie katalogów operuje serwer. Jeżeli lista katalogów i plików pokrywa się ze strukturą utworzoną na potrzeby serwera, to wszystko jest w porządku! Aby sprawdzić, czy wszystko działa, po prostu za pomocą przeglądarki WWW próbujemy połączyć się z naszym serwerem.

Oczywiście może się zdarzyć, że serwer nie zostanie prawidłowo uruchomiony. Wówczas należy sprawdzić komunikaty zapisane w pliku error.log. Z dużym prawdopodobieństwem będziemy wtedy musieli przekopiować dodatkowe pliki konfiguracyjne, np. /etc/mime.types, lub poprawić wybrane ścieżki w plikach konfiguracyjnych.

Na koniec pozostaje nam przepisanie skryptu odpowiedzialnego za uruchamianie Apache’a podczas startu systemu, by serwer wywoływany był w sposób, jak pokazaliśmy wcześniej. W niektórych specyficznych wypadkach będziemy musieli także poprawić konfigurację sysloga, logrotate i innych pochodnych programów współpracujących z Apache'em, np. Webalizera.

Co to jest .htaccess

Wielu osobom skrót .htaccess kojarzy się przede wszystkim z możliwością kontrolowania dostępu do strony internetowej za pomocą hasła. I choć jest to rzeczywiście jedno z bardziej popularnych zastosowań tego pliku, to jego rola jest znacznie szersza. Mechanizm .htaccess został zaprojektowany jako narzędzie do zmiany konfiguracji Apache’a w odniesieniu do pojedynczych katalogów na serwerze. W ten sposób nawet zwykły użytkownik może zmodyfikować ustawienia Apache’a, aktywując funkcje obsługi skryptów CGI i przetwarzania dyrektyw SSI czy ograniczając dostęp osób do strony z konkretnego adresu IP. Pliki .htaccess są także wykorzystywane do przygotowywania własnych stron błędów generowanych przez serwer. I to wszystko jest możliwe na poziomie pojedynczego katalogu w serwisie internetowym. Dla wszystkich naraz lub każdego z osobna.

Warto jednak wiedzieć, że ustawienia wprowadzane do konfiguracji przez .htaccess mogą być równie dobrze definiowane na poziomie głównego pliku ustawień Apache’a. Jakby tego było mało, dokumentacja serwera wprost odradza stosowanie .htaccess, jeżeli nie mamy ku temu wyraźnych przesłanek. Kiedy zatem nie powinniśmy używać tego mechanizmu? Podstawowa odpowiedź na to pytanie brzmi: wtedy, gdy mamy dostęp do plików konfiguracyjnych serwera. Reguły zapisane w .htaccess możemy z powodzeniem zawrzeć w ramach dyrektywy w głównym pliku ustawień Apache’a. Podejście to ma dwie kluczowe przesłanki. Pierwsza z nich związana jest ze zwiększonym obciążeniem serwera. Komputer, który musi przetwarzać dodatkowe reguły zapisane w kilku-kilkudziesięciu plikach konfiguracyjnych, potrzebuje więcej zasobów. Druga dotyczy bezpieczeństwa: jeżeli udostępniamy możliwość zmiany konfiguracji Apache’a, to w pewnym zakresie tracimy nad nim kontrolę. Użytkownicy mogą modyfikować jego ustawienia, co potencjalnie może prowadzić do naruszenia zasad bezpieczeństwa.

Mimo tych zastrzeżeń mechanizm .htaccess jest bardzo przydatnym narzędziem. Jeśli korzystamy z usług dostawcy hostingu, to dostęp do .htaccess umożliwi nam uruchomienie serwera WWW zgodnie z naszymi oczekiwaniami. Z drugiej strony, jeżeli jesteśmy właścicielami serwera i mamy do niego dostęp z uprawnieniami administratora, powinniśmy rozważyć konfigurację Apache’a na poziomie głównych plików konfiguracyjnych.

Admin musi pozwolić

Włączenie mechanizmu .htaccess odbywa się w głównych plikach konfiguracyjnych Apache’a. To właśnie tu decydujemy, czy możliwe będzie użycie plików .htaccess, a jeżeli tak, to w jakim zakresie. Służy do tego dyrektywa AllowOverride definiowana w sekcji dla głównego katalogu serwera lub jego podkatalogów. Dyrektywa ta może przyjmować wartość None, All, AuthConfig, FileInfo, Indexes, Limit oraz Options. Jak łatwo się domyślić, ustawienie tej opcji na
AllowOverride None

wyłącza użycie plików .htaccess. Serwer nie uwzględni wówczas konfiguracji w nich zapisanej, nawet jeżeli istnieją one w odpowiednich katalogach. Z kolei zastąpienie słowa None wpisem All zezwoli na użycie .htaccess w pełnym zakresie. Administrator może również przyznać uprawnienia tylko do zmiany niektórych jego ustawień. Służą do tego dyrektywy grup:
AuthConfig – włączenie mechanizmów autoryzacji odwiedzających stronę,
FileInfo – zmiana typu dokumentów (MIME, strony błędów),
Indexes – modyfikacja ustawień związanych z obsługą katalogów (strona główna, listowanie katalogów),
Limit – limitowanie dostępu do strony za pomocą mechanizmu zezwól/odmów (allow/deny),
Options – kontrolowanie opcji specyficznych dla katalogów (np. włączanie CGI, SSI itd.).

Opcje te można ze sobą łączyć, a zatem, aby zezwolić użytkownikom na zmianę konfiguracji serwera w zakresie autoryzacji i limitowania dostępu do serwera w ustawieniach Apache’a dla wybranego katalogu (sekcja Directory), wprowadzamy zapis:
AllowOverride AuthConfig Limit

Szczegółowe informacje na ten temat zostały zawarte w dokumentacji Apache’a [1]. Warto ją przeczytać, jeżeli chcemy dokładnie poznać znaczenie dyrektywy AllowOverride.

Choć poniższą poradę należy traktować raczej jako ciekawostkę, to niektórzy zechcą zrobić z niej użytek. Warto wiedzieć, że plik .htaccess może mieć dowolną inną nazwę, o ile wskażemy to w konfiguracji Apache’a. Służy do tego dyrektywa AccessFileName definiowana w ustawieniach serwera. Ma ona następującą składnię:
AccessFileName .configuration

gdzie .configuration oznacza nową nazwę pliku, który będzie odczytywany w poszukiwaniu lokalnej konfiguracji serwera.

Tworzenie .htaccess

Plik .htaccess jest zwykłym plikiem tekstowym ASCII. Jest on czytelny dla człowieka i może zostać utworzony za pomocą dowolnego edytora, np. Notatnika w Windows czy Vim lub Emacs w Linuksie. Zachowując zmiany, warto zwrócić uwagę na dość nietypową, szczególnie w środowisku Windows, jego nazwę. Rozpoczyna się ona kropką, po której następuje coś na kształt rozszerzenia. I choć jest to plik tekstowy, nie ma on przyrostka .txt. Tak przygotowany zbiór przenosimy na serwer np. za pomocą protokołu FTP. Trzeba pamiętać, aby skopiować go w trybie transmisji ASCII, a nie binarnym.

Zbiór .htaccess „działa” w obrębie katalogu, w którym został umieszczony, oraz wszystkich jego podfolderach. Jeżeli zatem zapiszemy .htaccess w katalogu głównym serwera, zmiany w nim wprowadzone obejmą swoim zasięgiem cały serwis WWW. Nic nie stoi na przeszkodzie, aby w każdym z podkatalogów zdefiniować osobny plik .htaccess. Ale uwaga: parametry ustawień zawarte w .htaccess zapisanych w danym katalogu zastępują te ustalone na poziomie głównego pliku konfiguracyjnego serwera i wszystkich plików umieszczonych wyżej w strukturze drzewa katalogów.

Dostęp na hasło

Użycie haseł to najprostsza metoda na ograniczenie dostępu do naszej strony lub wybranego jej katalogu. Zanim odwiedzający obejrzy zawartość serwisu, będzie musiał wprowadzić nazwę użytkownika i hasło. Choć mechanizm ten możemy zaimplementować, korzystając z języków programowania (PHP, JavaScript itd.), znacznie szybciej podobny efekt uzyskamy, gdy zastosujemy zbiory .htaccess.

Na początek przygotowujemy plik zawierający hasła dostępu wraz ze skojarzonymi z nimi osobami (nazwami użytkownika). Jest to zbiór tekstowy .htpasswd, w którym hasła są zaszyfrowane za pomocą algorytmu MD5. Z tego też względu do wykonania tego zadania posłużymy się programem htpasswd dostarczanym wraz z Apache’em. Jest on zazwyczaj dostępny w domyślnej ścieżce przeszukiwania serwera, a jego uruchomienie powinno mieć następującą postać:
htpasswd -c /home/apache/hasla/.htpasswd janek

gdzie /home/apache/hasla/ jest ścieżką do katalogu, w którym będziemy przechowywali hasła, .htpasswd nazwą pliku je przechowującym, a janek to użytkownik, dla którego definiujemy dostęp. Na koniec pozostaje nam dwukrotnie wprowadzić hasło i pamiętać, że pliki te powinny być przechowywane poza miejscem, w którym udostępniamy stronę WWW. Inaczej mówiąc, hasła zapisujemy w katalogu, do którego ma dostęp serwer Apache, ale który nie jest osiągalny z poziomu przeglądarki internetowej. Aby dopisać dodatkowych użytkowników do pliku z hasłami w kolejnym wywołaniu htpasswd, pomijamy parametr -c.

Gdy pierwszy krok mamy za sobą, w pliku .htaccess definiujemy reguły autoryzacji użytkowników. Przykładowe wpisy mogą mieć następującą postać:
AuthType Basic
AuthName "Galeria zdjec"
AuthUserFile /home/apache/hasla/.htpasswd
Require user janek franek iza

gdzie parametr AuthUserFile określa ścieżkę do pliku .htpasswd, janek, franek oraz iza są natomiast osobami uprawnionymi do przeglądania danego zasobu. Zamiast wymieniać użytkownika z osobna, możemy posłużyć się parametrem valid-user:
require valid-user

Wówczas wszyscy użytkownicy mający odpowiednie wpisy w .htpasswd będą mogli logować się do serwisu. Pole AuthName zawiera informację, którą możemy przekazać użytkownikom, a która identyfikuje nasz serwis. Pojawi się ona w okienku logowania do strefy chronionej hasłem. Z kolei AuthType wskazuje typ autoryzacji HTTP. W tym przypadku jest to Basic.

Nasze reguły możemy wzbogacić o funkcję ograniczającą dostęp do strony tylko z wybranego adresu IP, puli adresów lub domeny, np.:
Access allow 40.53.218.11
Access allow serwer.pl

Wróćmy jednak do pliku .htpasswd. Przykładowa jego zawartość może mieć postać:
janek:Epowp5bTSabac
franek:IqOcGapAdnEmI

Choć hasła to zwykły ciąg znaków, już na pierwszy rzut oka widać, że są one zaszyfrowane przez program htpasswd. Jego użycie jest możliwe tylko wówczas, gdy mamy dostęp do linii komend serwera. Dostawcy hostingu niechętnie jednak oferują taką usługę. W takim przypadku musimy poradzić sobie w inny sposób. Pierwszy polega na wykorzystaniu mechanizmów w panelu administracyjnym serwera WWW. Operator umożliwia wówczas automatyczne wygenerowanie użytkowników i skojarzonych z nim haseł z poziomu zwykłej przeglądarki internetowej. Drugie rozwiązanie opiera się na programach działających online. Potrafią one wygenerować zaszyfrowane hasła, które następnie kopiujemy do pliku .htpasswd i przenosimy na serwer. Przykładowe generatory znajdziemy na stronach .htpasswd Content Generator [2] oraz .htpasswd generator [3].

Strony błędów

„404 File Not Found” – takim standardowym komunikatem serwer poinformuje nas, że strona, której zażądaliśmy, nie została odnaleziona. To jeden z najczęściej spotykanych błędów występujących podczas przeglądania Internetu. Predefiniowanych kodów zwracanych przez serwer jest znacznie więcej i dotyczą one m.in. wewnętrznych błędów serwera czy nieautoryzowanego dostępu do serwisu. Kody statusu nie muszą jednak wcale oznaczać błędu. Przykładowo: komunikat 200 OK. wysłany do przeglądarki informuje o odnalezieniu strony na serwerze. Obszerną listę kodów znajdziemy na stronach Wikipedii [4] oraz organizacji W3C [5].

Administrator strony internetowej może samodzielnie zadecydować, jaką akcje ma podjąć Apache w przypadku wystąpienia błędu. W praktyce najczęściej stosuje się mechanizm wyświetlania własnej strony (dokumentu) błędu zawierającej zrozumiały dla przeciętnego użytkownika przekaz o zaistniałej sytuacji zamiast surowego, technicznego komunikatu od serwera. Strony błędów mogą zostać zdefiniowane w pliku .htaccess. Jego konstrukcja jest bardzo prosta:
ErrorDocument 404 /komunikaty/nieznaleziono.html
ErrorDocument 403 "Nie masz dostępu do tej strony."
ErrorDocument 500 "/cgi-bin/obsluga_bledow.pl"
ErrorDocument 403 http://www.serwer.pl

Po słowie kluczowym ErrorDocument należy podać kod statusu oraz podejmowaną przez serwer akcję. Może to być załadowanie innej strony WWW (pierwszy wiersz przykładu), wyświetlenie komunikatu tekstowego (drugi wiersz), wywołanie skryptu (trzeci wiersz) czy po prostu przekierowanie do innego serwisu, także z innej domeny (czwarty wiersz). W przypadku gdy definiujemy własne strony błędów, np. w postaci pliku HTML, należy je odpowiednio wcześniej przygotować, przenieść na serwer i wskazać ścieżkę dostępu.

Zmiana strony startowej

Gdy wpiszemy w przeglądarce adres strony WWW obsługiwanej przez Apache’a, to przy standardowej jego konfiguracji automatycznie wyświetlana jest predefiniowana strona startowa. Jest to najczęściej plik index.html lub index.php umieszczony w głównym katalogu serwera. To powszechnie przyjęte nazewnictwo ma swoje odzwierciedlenie w konfiguracji Apache’a. Nazwa pliku startowego definiowana jest bowiem za pomocą parametru DirectoryIndex i najczęściej przyjmuje postać:
DirectoryIndex index.html index.htm index.php index.cgi

Kolejność wpisów ma tutaj znaczenie. I tak Apache najpierw będzie szukał pliku index.html, później index.htm, a na końcu index.cgi. Jeżeli z jakichś względów chcemy to domyślne zachowanie serwera zmienić, możemy użyć pliku .htaccess. Wystarczy, że umieścimy w nim wpis:
DirectoryIndex startowa.html

który nadpisze wartość tego parametru z głównego pliku konfiguracyjnego Apache’a. Od tego momentu domyślną stroną startową będzie plik startowa.html.

Blokowanie dostępu do strony

O ile .htpasswd umożliwia limitowanie dostępu do serwisu na poziomie użytkownika, tak mechanizm allow/deny pozwoli nam zablokować lub zezwolić na wyświetlanie strony osobom łączącym się ze wskazanego adresu IP, puli adresów czy domeny. Przykładowa konstrukcja wpisu w .htpasswd może wyglądać następująco:
order allow,deny
deny from serwer.pl
deny from 40.53.218.11
deny from 40.53.217.
allow from all

Parametr order pozwala ustalić kolejność przetwarzania dyrektyw allow i deny. W przypadku wpisu order allow,deny najpierw nakładane są warunki zezwalające na dostęp, a dopiero później te, które go zabraniają.

Na liście wpisów zamieszczamy tych, którym chcemy zablokować dostęp (w przykładzie tych z domeny serwer.pl oraz adresu 40.53.218.11 i całej puli adresów 40.53.217.), a następnie zezwalamy pozostałym (from all) na przeglądanie zasobów serwera.

CGI i SSI

Za pomocą .htaccess ustalimy także wiele innych parametrów pracy Apache’a. Nie sposób ich wszystkich wymienić, więc przytoczymy te najpopularniejsze. Aby możliwe było ich zaaplikowanie, dyrektywa AllowOverride musi być ustawiona na All lub w węższym zakresie na Options. Jeśli wybrany katalog serwera służy do przechowywania i wykonywania skryptów CGI, tworzymy dyrektywę:
Options +ExecCGI

I analogicznie, aby odebrać te prawa, jako parametr Options wpisujemy -ExecCGI. W podobny sposób włączymy obsługę mechanizmu SSI (Server Side Includes). Pozwala on na dynamiczne osadzanie wielu stron w jednym dokumencie. Jeżeli chcemy aktywować SSI dla wybranego katalogu, w .htaccess zamieszczamy wpis:
Options +Includes

Dodatkowo sprawdźmy, czy w głównym pliku konfiguracyjnym Apache’a zdefiniowano sposób obsługi CGI i SSI. Służą do tego dyrektywy:
AddHandler cgi-script .cgi
AddType text/html .shtml
AddOutputFilter INCLUDES .shtml

Wpisy te możemy równie dobrze zamieścić w pliku .htaccess, o ile administrator przyznał dodatkowo możliwość modyfikacji ustawień z grupy FileInfo.

Listowanie katalogów

Na koniec chyba najprzyjemniejsza i najprostsza do zrozumienia dyrektywa Indexes. W niektórych domyślnych konfiguracjach serwera jest ona włączona. Jej działanie polega na wyświetlaniu zawartości katalogu, jeśli nie została wprowadzona pełna nazwa pliku oraz gdy nie istnieje plik startowy definiowany dyrektywą DirectoryIndex. Funkcja ta jest natomiast niezbyt chętnie udostępniana przez administratorów. Nie powinniśmy bowiem pozwalać odwiedzającym naszą stronę na przeglądanie zawartości katalogu, o ile oczywiście nie ma ku temu wyraźnych przesłanek. Aby zablokować listowanie wybranego katalogu, w pliku .htaccess umieszczamy wpis:
Options -Indexes

Analogicznie jak w poprzednich przypadkach, aby włączyć domyślnie nieaktywną funkcję listowania, znak minusa zastępujemy plusem. Warto zwrócić uwagę także na dyrektywę IndexIgnore. Pozwala ona na selektywne ograniczenie listowanych plików. Warto sprawdzić, czy nie jest ona już zdefiniowana w głównym pliku konfiguracyjnym. W wersji 2 serwera w dystrybucji znajduje się następujący wpis:
IndexIgnore .??* *~ *# RCS CVS *,v *,t

Ogranicza on listowanie m.in. plików rozpoczynających się od kropki, czyli choćby omawianego zbioru .htaccess. Zastosowano tutaj symbole wieloznaczne, np. * zastępującą dowolny ciąg znaków. W razie potrzeb możemy tę listę rozszerzyć o własne wpisy. Jeżeli nie chcemy, aby podczas wyświetlania zawartości katalogów były widoczne pliki graficzne (GIF, JPEG i PNG), możemy tę dyrektywę rozszerzyć o dodatkowe parametry:
IndexIgnore .??* *~ *# RCS CVS *,v *,t *.gif *jpg *jpeg *.png

Przedstawione zagadnienia nie wyczerpują możliwości, jakie daje użycie pliku .htaccsess. Żeby zachęcić do lepszego ich poznania, powiedzmy tylko tyle, że możliwe jest blokowanie botów czy bezpośrednich linków do plików na naszym serwerze.



Warto odwiedzić

[1] AllowOverride

http://httpd.apache.org/docs/2.2/mod/core.html#allowoverride

[2] .htpasswd Content Generator

http://home.flash.net/cgi-bin/pw.pl

[3] .htpasswd generator

http://www.htaccesstools.com/htpasswd-generator/

[4] Kody statusu protokołu HTTP

http://pl.wikipedia.org/wiki/Kod_odpowiedzi_HTTP

[5] Kody statusu protokołu HTTP (język angielski)

http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html