2006 04 Kryptografia w PHP [Kryptografia]


Bezpieczeństwo
Kryptografia w PHP
Stopień trudności: lll
Aukasz Lach, Michał Stanowski
Prawdopodobnie każdy z nas wie, czym jest
kryptografia. Bierzemy porcję informacji
(np. tekstu) i szyfrujemy ją tak, aby nikt
nieuprawniony nie był w stanie jej odczytać.
Z kryptografią mamy do czynienia na co dzień
 czy to korzystając z banku internetowego, czy
też wysyłając szyfrowanego maila. I to wszystko
z wykorzystaniem PHP.
ikipedia definiuje kryptogra- tykule pokażemy, w jaki sposób można
fię jako  naukę zajmującą się efektywnie korzystać ze wspomnianych
Wukładaniem szyfrów . W prak- funkcji na podstawie trzech praktycznych
tyce jest to konwersja jednej informacji przykładów.
w drugą za pomocą złożonych obliczeń ma-
tematycznych (szyfrowanie) oraz ewentual- System bezpiecznego
na konwersja tejże informacji do stanu pier- logowania
wotnego (deszyfrowanie). W kontekście Zacznijmy od stworzenia bezpieczne-
aplikacji internetowych jest to dość często go systemu logowania. Jest to idealny
spotykana dziedzina, zarówno w małych, przykład na wykorzystanie funkcji kryp-
jak i w dużych, komercyjnych serwisach tograficznych dostępnych w PHP. W na-
 podczas logowania się do banku interne-
towego wpisywane przez nas dane przesy-
W SIECI
Co należy wiedzieć...
łane są bezpiecznym, szyfrowanym łączem
Przydatna będzie podstawowa znajo-
SSL, a wysyłając poufne wiadomości e-ma-
mość zagadnień kryptografii oraz PHP.
l
http://php.net/mcrypt il korzystamy z systemu PGP, chroniącego
 MCrypt
ich treść przed osobami trzecimi.
l
http://php.net/mhash
Co obiecujemy...
PHP zawiera szereg funkcji pozwala-
 MHash
Z artykułu dowiesz się, jak zbudować
l
http://phpsec.org/
jących na szyfrowanie i generowanie ha-
bezpieczny system logowania oraz apli-
 PHP Security Consortium
szów dowolnych łańcuchów znaków czy kację do składowania i szyfrowania pli-
l
http://php.net/security
ków na serwerze WWW. Na przykła-
 Bezpieczeństwo PHP
zawartości plików. Część z nich dostęp-
l
http://pajhome.org.uk/crypt/ dach tych przedstawimy najpopularniej-
na jest natywnie, jednak duża większość
md5
sze i najlepsze rozwiązania kryptogra-
 funkcje haszujące dla JS przy wykorzystaniu zewnętrznego rozsze-
ficzne w PHP.
rzenia, dołączonego do PHP. W tym ar-
www.phpsolmag.org PHP Solutions Nr 4/2006
34
Kryptografia w PHP Bezpieczeństwo
szym, bezpiecznym systemie hasło wpisa-
ne przez użytkownika przesyłane będzie
Algorytmy i funkcje haszujące
w formie funcji skrótu, nawet dwukrotnie:
Funkcją haszującą (czy też funkcją skrótu) nazywamy funkcję, która dowolnemu łańcu-
chowi znaków przyporządkowuje inną, unikalną wartość nazywaną powszechnie haszem
za pierwszym razem przez algorytm MD5,
(ang. hash) lub skrótem. Algorytm skrótu jest jednokierunkowy, otrzymanie pierwotnej war-
a następnie HMAC-MD5.
tości na podstawie wcześniej wygenerowanego skrótu wymaga ogromnej mocy oblicze-
Przesyłana wartość będzie prawidłowa
niowej i jest praktycznie niemożliwe. Istotną właściwością funkcji skrótu jest to, że zmiana
tylko i wyłącznie raz, ponieważ klucz pu-
choć jednego znaku łańcucha wejściowego, bez względu na jego długość, powoduje wy-
generowanie całkiem innej wartości skrótu.
bliczny, potrzebny w procesie szyfrowania,
Nie posiadając dołączonego do PHP rozszerzenia MHash mamy do dyspozycji pięć
będzie za każdym razem unikalny  dyna-
standardowo dostępnych funkcji pozwalających generować hasze dla trzech, najbardziej
micznie tworzony po stronie serwera.
popularnych algorytmów  CRC32, MD5 oraz SHA1. Najnowsza wersja PHP5 udostęp-
Taki system okaże się bardzo pożą-
niać będzie ponadto rozszerzenie Hash (http://php.net/hash), które zawiera praktycznie
wszystkie algorytmy dostępne w MHash, a przy tym jest domyślnie zintegrowane z PHP
dany, kiedy na serwerze nie posiadamy
i nie wymaga żadnych dodatkowych bibliotek czy konfiguracji. Jednak póki co rozszerze-
SSL, a chcemy przesyłać zaszyfrowane
nie Hash jest dostępne wyłącznie do testów i nie powinno być powszechnie wykorzysty-
dane. W przeciwieństwie do tradycyjnego
wane tym bardziej, że zarówno sama zasada jego działania, jak i lista dostępnych algoryt-
systemu logowania, ten skutecznie ochro-
mów może się jeszcze zmienić.
ni użytkowników przez atakami typu snif- Mimo to, dostępne natywnie w PHP algorytmy haszowania są w zupełności wystar-
czające, bez różnicy na rozmiar tworzonego projektu. Algorytmy takie jak CRC32 i MD5
fing, polegających na podsłuchaniu infor-
są powszechnie i z powodzeniem wykorzystywane do tworzenia sum kontrolnych plików
macji wymienianych pomiędzy klientem
lub poufnych danych, które muszą być dostępne jedynie w postaci umożliwiającej walida-
a serwerem, a co w konsekwencji pozwa-
cję (np. hasła). Tabela 1 zawiera algorytmy dostępne natywnie w PHP oraz poprzez roz-
la na przejęcie wpisanej nazwy użytkowni- szerzenie MHASH.
ka oraz hasła i wykorzystanie ich do za-
logowania. Dodatkowo, wszystkie hasła
przechowywane będą jedynie w postaci gorytm HMAC wykorzystamy do wygene- wygenerowanie nowego klucza, a co za
skrótu MD5, także ich ewentualne pozna- rowania skrótu hasła, dołączając do nie- tym idzie, stworzony w oparciu o niego
nie przez osoby niepowołane jest całkowi- go losowy klucz wygenerowany po stro- hasz będzie miał całkiem inną wartość.
cie niegrozne (przyjmując oczywiście, że nie serwera. PHP nie posiada implemen- Co nam to daje? Otóż nawet w przypad-
hasła mają przyzwoitą długość, czyli przy- tacji HMAC algorytmu MD5, także musimy ku podsłuchania danych przez osobę
najmniej 10 znaków). Podstawowe infor- ją najpierw napisać opierając się o dostęp- trzecią, zdobyte w ten sposób informa-
macje dotyczące funkcji haszujących za- ną dokumentację (http://www.ietf.org/rfc/ cje będą całkowicie bezużyteczne. Skup-
wiera Ramka Algorytmy i funkcje haszu- rfc2104.txt). Kod zródłowy funkcji hmac_md5 my się najpierw na części HTML kodu
jące. Na Rysunku 1 przedstawiliśmy sche- przedstawiliśmy na Listingu 1. zródłowego, która umieszczona jest na
mat tworzonego systemu bezpiecznego Dodatkowym atutem przedstawio- Listingu 2. W pierwszych linijkach skryp-
logowania. nej implementacji jest to, że pozwala nie tu dołączamy plik języka JavaScript
W naszym przykładzie skorzystamy tylko na wygenerowanie skrótu HMAC- o nazwie md5.js, który zawiera dwie klu-
również z wersji HMAC algorytmu MD5. MD5, ale również HMAC-SHA1, tak więc czowe dla nas funkcje  hex_md5 oraz
HMAC-MD5 jest rozszerzeniem funkcji mamy do dyspozycji dwa dodatkowe al- hex_hmac_md5, będące odpowiednika-
skrótu MD5 i pozwala na dołączenie do- gorytmy do wykorzystania w naszych mi funkcji md5 i hmac_md5, dostępnych od
datkowego, dowolnego klucza. Wygenero- projektach. strony skryptu PHP. Poniżej umieszczo-
wany w ten sposób łańcuch znaków mo- W naszym systemie zakładamy, że ny jest kod zródłowy funkcji parseForm,
że być wówczas przesłany do odbiorcy, przesłane przez użytkownika hasło w po- która wywoływana jest tuż przed przesła-
który, posiadając owy sekretny klucz, mo- staci skrótu HMAC-MD5 będzie prawdzi- niem formularza. Formularz ten zawarty
że sprawdzić poprawność przesłanego we tylko i wyłącznie raz. Ponowne otwar- jest w części body dokumentu i zawiera
ciągu. W naszym systemie logowania al- cie czy przeładowanie strony spowoduje cztery istotne pola:
" key  pole typu hidden zawierają-
hasło hasz hasła ce wygenerowany po stronie serwe-
KLIENT MD5 HMAC-MD5
ra unikalny klucz, wykorzystywany na
etapie logowania przez wersję HMAC
hasz hasła
nazwa
poł czony
klucz funkcji haszującej,
użytkownika
z kluczem
publiczny
" js  pole typu hidden, którego wartość
publicznym
określa, czy przeglądarka użytkowni-
ka obsługuje JavaScript. Jego domyśl-
SERWER ż danie HTTP
ną wartością jest 0 (zero), zamieniane
rozpoczęcie
przed przesłaniem na 1 (jeden) w koń-
logowania
cowych linijkach funkcji doLogin,
" username  pole typu text, zawierają-
Rysunek 1. Schemat działania systemu bezpiecznego logowania
ce wpisaną nazwę użytkownika,
4/2006 PHP Solutions Nr 4/2006 www.phpsolmag.org
35
Bezpieczeństwo Kryptografia w PHP
" password  pole typu password, zawie- pieczeństwa. Przyjrzyjmy się teraz innej Podstawy kryptografii
rające wpisane hasło. funkcji dostępnej natywnie w PHP, pozwa-  crypt
lającej na szyfrowanie łańcuchów znaków Wbrew przypuszczeniom funkcja crypt
Rola pola js jest bardzo ważna  w przy- za pomocą takich algorytmów jak DES czy pozwala na szyfrowanie w jedną stronę,
padku, gdy jego wartość jest równa 0, wie- Blowfish. Mowa tu o funkcji crypt nie ma funkcji decrypt, która pozwoliła-
my, że dane nazwy użytkownika i hasła
przesłane zostały w postaci jawnej, jed-
Listing 1. Implementacja algorytmu HMAC-MD5 dla PHP
nak mimo to nadal jesteśmy się w stanie
bezproblemowo zalogować. Wróćmy jed-
define('HMAC_MD5', 1);
nak do kodu zródłowego omawianej funk-
define('HMAC_SHA1', 2);
cji. W przypadku nie podania nazwy użyt-
function hmac($string, $key, $algorithm = HMAC_MD5) {
kownika lub hasła, wyświetlamy stosowny
$algorithm = $algorithm == HMAC_MD5 ? 'md5' : 'sha1';
komunikat i przenosimy kursor do pustego
if (function_exists('hash_hmac'))
return hash_hmac($algorithm, $string, $key);
pola. W innym wypadku modyfikujemy za-
if (isset($key{64}))
wartość pola zawierającego hasło na hasz
$key = pack('H*', $algorithm($key));
HMAC-MD5 skrótu MD5 wpisanego hasła
$key = str_pad($key, 64, "\0");
oraz unikalnego klucza, dostępnego w po-
$iPad = str_repeat("\x36", 64);
lu key. Dodatkowo ustawiamy wartość po- $oPad = str_repeat("\x5c", 64);
return $algorithm(($key ^ $oPad).pack('H*', $algorithm(($key ^ $iPad) .
la js na 1 i zezwalamy na wysłanie formu-
$string)));
larza zwracając wartość true.
}
Zobaczmy teraz, co dzieje się po stro-
function hmac_md5($string, $key) {
nie serwera  pełny kod PHP opisywane-
return hmac($string, $key, HMAC_MD5);
go przykładu znajduje się na Listingu 3.
}
?>
Główna część skryptu to funkcja doLogin,
której zadaniem jest sprawdzenie nazwy
Listing 2. Kod HTML systemu bezpiecznego logowania
użytkownika i hasła. W przypadku nie po-
dania którejkolwiek z tych danych zwraca-
my wartość -1. Następnie sprawdzamy po- "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

prawność przesłanego z poziomu formula-

rza klucza (pole key) z tym zapisanym
PHP Solutions :: hmac_md5
w sesji. Jeśli do tego momentu wszyst-

ko zakończyło się pomyślnie, nawiązuje-

my połączenie z bazą danych i pobiera-
komunikatu o błędzie. W przypadku, gdy
zwrócona przez funkcję doLogin wartość
if (!empty($errorString))
jest łańcuchem znaków, traktujemy ją ja- echo '
'.$errorString.'
';
?>
ko nazwę użytkownika i zapisujemy do

zmiennej sesji przekierowując jednocze-

nelu administracyjnego. Na końcu modyfi-

kujemy wartość zmiennej klucza zapisując


w niej nową, unikalną wartość.

Reasumując: z pomocą jednej funkcji


haszującej stworzyliśmy mały objętościo-

wo skrypt o wielkich możliwościach, za-

pewniający użytkownikom logującym się
do naszego serwisu wysoki poziom bez-
www.phpsolmag.org PHP Solutions Nr 4/2006
36
Kryptografia w PHP Bezpieczeństwo
by na odszyfrowanie informacji. W prakty-
Listing 3. Kod PHP systemu bezpiecznego logowania
ce więc jest to kolejna funkcja haszująca.
Zobaczmy, jak na jej podstawie możemy
zbudować znacznie prostszy skrypt uwie-
function doLogin() { rzytelniania, oparty o protokół HTTP i al-
// Nie podano nazwy użytkownika lub hasła
gorytm DES.
if (empty($_POST['username']) ||
Zasada działania każdego systemu
empty($_POST['password']))
uwierzytelniania jest niemal identyczna.
return -1;
Po podaniu nazwy użytkownika i hasła
$js = $_POST['js'];
$key = $_SESSION['key']; skrypt dokonuje porównania tych danych
z informacjami przechowywanymi w bazie
// Klucz przesłany w rządaniu HTTP nie zgadza się z tym
danych lub pliku. Najczęściej, ze wzglę-
// zapisanym w sesji
dów bezpieczeństwa, hasło użytkownika
if ($key != $_POST['key'])
nie jest przechowywane w postaci jawnej
return -2;
 do bazy zapisujemy hasz hasła. Do two-
// Wyszukanie rekordu administratora
rzenia tego rodzaju haszy możemy użyć
// o podanej nazwie użytkownika
funkcji crypt. Jest ona standardowo do-
$mysql_handle = mysql_connect('host', 'username',
stępna w każdej instalacji PHP, więc nie
'password')
ma potrzeby ponownej komplikacji PHP,
or die(mysql_error());
mysql_select_db('test', $mysql_handle) czy modyfikacji pliku konfiguracyjnego.
or die(mysql_error());
Spróbujmy na początek stworzyć pro-
$mysql_result = mysql_query('SELECT username, password
sty przykład oparty o funkcję crypt. Jego
FROM admin
kod zródłowy znajduje się na Listingu 4.
WHERE username = "'.mysql_real_escape_string(
Przy każdym przeładowaniu strony/
$_POST['username'], $mysql_handle).'"');
skryptu uzyskamy unikalną wartość ha-
// Brak rekordu administratora
sza. Dzieje się tak dlatego, że za każdym
// o podanej nazwie użytkownika
razem tworzony jest losowy ciąg znaków
if (mysql_num_rows($mysql_result) == 0)
 $salt  niezbędny w procesie tworze-
return -3;
nia skrótu. Od drugiego argumentu wywo-
$row = mysql_fetch_assoc($mysql_result);
łania omawianej funkcji zależy jaki algo-
// Walidacja hasła w zależności od tego,
rytm zostanie wykorzystany. I tak dla dwu-
// czy wykorzystany został JavaScript
znakowej wartości zmiennej $salt będzie
if ($js) {
to standardowy algorytm DES, dla dzie-
require 'hmac_md5.php';
więcioznakowej  algorytm DES w wersji
if (hmac_md5($row['password'], $key) != $_POST['password'])
return -4; rozszerzonej. Aby wykorzystać algorytm
} else {
MD5, za zmienna $salt musi składać się
if (md5($_POST['password']) != $row['password'])
z dwunastu znaków z początkowym łań-
return -4;
cuchem $1$, zaś dla algorytmu Blowfish
}
będzie to szesnaście znaków rozpoczy-
// Logowanie powiodło się, zwracamy nazwę użytkownika
return $row['username']; nając od $2$ lub $2a$. Zmienna $salt jest
}
pózniej dołączana na początek wygenero-
session_start();
wanego skrótu.
$errorString = '';
Wróćmy do naszego przykładu,
$loginResult = doLogin();
w którym chcemy stworzyć skrypt uwie-
switch ($loginResult) {
case -1: break; rzytelniania poprzez protokół HTTP. Na-
case -2: $errorString =
zwy użytkowników i ich hasła trzymane
'Nieprawidłowa wartość klucza'; break;
będą w pliku tekstowym (Listing 5).
case -3: $errorString =
Warto wspomnieć najpierw o cieka-
'Nieprawidłowa nazwa użytkownika'; break;
wej właściwości funkcji crypt. Jeśli spró-
case -4: $errorString =
'Nieprawidłowe hasło'; break; bujemy stworzyć hasz informacji przesła-
default:
nej przez użytkownika (przykładowo ha-
$_SESSION['username'] = $loginResult;
sła) podając jako $salt hasz trzymany
header('Location:
w bazie danych lub pliku (wzorzec hasła),
http://server.com/admin/panel.php');
funkcja powinna zwrócić nam identyczny
die();
} skrót. Sytuacja ta ma miejsce tylko wtedy,
$_SESSION['key'] = md5(uniqid(rand(), true));
gdy podane hasło jest zgodne z tym wy-
korzystywanym przy tworzeniu skrótu po
?>
raz pierwszy. Wykorzystamy tę własność
w naszym skrypcie uwierzytelniania.
PHP Solutions Nr 4/2006 www.phpsolmag.org
37
Bezpieczeństwo Kryptografia w PHP
Pamiętajmy, że uwierzytelnianie oparte na ne pliki i szczegółowe informacje o nich, Na początek coś prostego
protokole HTTP dostępne jest jedynie wte- takie jak wielkość czy typ MIME)  szyfrujemy fragment tekstu
dy, jeśli nasze PHP działa jako moduł Apa- przechowywać będziemy w bazie da- Zanim przejdziemy do implementacji na-
che. Jeżeli jest inaczej (czyli PHP działają- nych. Zapytanie SQL tworzące odpo- szej bezpiecznej składnicy danych, po-
ce jako CGI), nasz przykład nie zadziała. wiednią tabelę przedstawiliśmy na Li- znajmy schemat działania i możliwości
Przyjrzyjmy się Listingowi 6. Na po- stingu 7. W odpowiednich kolumnach rozszerzenia MCrypt. Na Listingu 8 przed-
czątku musimy sprawdzić, czy użytkownik przechowywać będziemy nazwę pliku, stawiony został przykładowy kod PHP, któ-
przesłał już swój login i hasło. Jeżeli nie, datę umieszczenia w bazie, typ MIME, rego zadaniem jest szyfrowanie podanego
wysyłamy odpowiednie nagłówki HTTP, a także długość oryginalnego pliku, klucz łańcucha znaków przy pomocy klucza,
które poinformują przeglądarkę, by wy- i sam plik w postaci zaszyfrowanej. a następnie jego odszyfrowanie.
świetlić odpowiednie okno logowania. Te
same nagłówki będą wysyłane, jeżeli po-
Listing 4. Przykład wykorzystania funkcji crypt
damy błędne dane logowania. Gdy użyt-
kownik przesłał nam już odpowiednie da-
$password = 'qwerty';
ne, musimy pobrać zawartość pliku, któ-
$salt = '$1$abcde$';
ry pełni funkcje naszej bazy i przechowuje
$hash = crypt($password, $salt);
hasła użytkowników. Przy pomocy funkcji
echo $hash;
explode podzielimy pobrane dane, oddzie- ?>
lając nazwy użytkowników i hasła. Ostat-
Listing 5. Format danych pliku z danymi użytkowników
ni krok to pętla, która przechodzi przez
wszystkie rekordy, sprawdzając, czy użyt-
admin:$1$Lp5.2//.$UMLhAWJJB9fLR.FU4gSAw1
kownik może być dopuszczony do danej
user:$1$hI3.Wd0.$thbtd1at0auCNfn7s5Bdy1
strony. Aby sprawdzić poprawność hasła,
Listing 6. Skrypt walidacji danych podczas autoryzacji
wykorzystujemy właściwość funkcji crypt
opisaną wcześniej.
Jak widać może być ona bez proble-
define('USERS_FILE', 'users.txt');
mu wykorzystania w celu stworzenia pro- if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW']))
{
stego systemu uwierzytelniania. Mimo
$users = explode("\n", file_get_contents(USERS_FILE));
wszystko jednak lepszym pomysłem jest
foreach($users as $user)
korzystanie z algorytmów takich jak MD5
{
czy SHA1 (czyli funkcji md5, sha1), ponie-
$user = explode(':', trim($user), 2);
waż algorytm DES ma znacznie mniejszą
if($user[0] == $_SERVER['PHP_AUTH_USER'])
{
złożoność, a przy tym podczas tworzenia
if(crypt($_SERVER['PHP_AUTH_PW'], $user[1]) != $user[1])
skrótu wykorzystywane jest tylko 8 pierw-
{
szych znaków.
header('WWW-Authenticate: Basic realm="Private"');
header('HTTP/1.0 401 Unauthorized');
Zaawansowana
exit;
}
kryptografia  MCrypt
break;
MCrypt jest rozszerzeniem PHP udostęp-
}
niającym metody pozwalające na szyfro-
}
wanie danych przy użyciu algorytmów ta-
}
kich jak DES, TripleDES, Blowfish, RC2
else
{
i wielu innych, lista najpopularniejszych al-
header('WWW-Authenticate: Basic realm="Private"');
gorytmów dostępnych dla tego rozszerze-
header('HTTP/1.0 401 Unauthorized');
nia umieszczona została w Tabeli 2. Opis
exit;
instalacji i konfiguracji biblioteki znajdu-
}
je się w Ramce Instalacja rozszerzenia
?>
MCrypt.
Listing 7. Struktura tabeli przechowującej dane zaszyfrowanych plików
MCrypt jest potężnym narzędziem,
dlatego też na jego podstawie stworzy-
CREATE TABLE 'secure_files' (
my dość rozbudowany przykład. Napi-
'id' int(11) unsigned NOT NULL auto_increment,
szemy aplikację, która pozwoli nam na 'name' varchar(100) default NULL,
'mime_type' varchar(30) default NULL,
przechowywanie na serwerze plików
'date' int(10) unsigned default '0',
dowolnego typu w postaci zaszyfrowa-
'length' varchar(255) default '0',
nej, a pobranie ich na lokalny dysk moż-
'key' varchar(32) default NULL,
liwe będzie jedynie po podaniu właści-
'data' text,
wego hasła, identycznego z tym uży- PRIMARY KEY ('id')
) TYPE=MyISAM;
tym w procesie szyfrowania dokumen-
tu. Wszystkie dane (czyli zaszyfrowa-
www.phpsolmag.org PHP Solutions Nr 4/2006
38
Kryptografia w PHP Bezpieczeństwo
Tabela 1. Algorytmy dostępne natywnie w PHP oraz poprzez rozszerzenie MHASH sca w pamięci. Korzystamy w tym celu
z funkcji mcrypt_generic_init, przekazu-
Nazwa algorytmu Natywnie / Nazwa funkcji MHASH / Nazwa stałej
jąc jej utworzone wcześniej uchwyty do
ALDER32 X  MHASH_ADLER32
modułu i wektora inicjującego, jak rów-
CRC32 X  crc32( ) X  MHASH_CRC32
nież wartość klucza, który będzie wyko-
GOST X  MHASH_GOST
rzystywany w procesie szyfrowania. Klucz
HAVAL128 X  MHASH_HAVAL128
został przycięty do maksymalnej długo-
ści obsługiwanej przez wybrany algorytm.
HAVAL160 X  MHASH_HAVAL160
Następnie wywołujemy funkcję mcrypt_
HAVAL192 X  MHASH_HAVAL192
generic, której wynikiem jest zaszyfrowa-
HAVAL256 X  MHASH_HAVAL256
ny łańcuch znaków. Po wszystkim zwal-
MD4 X  MHASH_MD4
niamy zarezerwowaną pamięć funkcją
MD5 X  md5( ), md5_file( ) X  MHASH_MD5
mcrypt_generic_deinit i kończymy pra-
cę z biblioteką MCrypt poprzez wywoła-
RIPEMD160 X  MHASH_RIPEMD160
nie mcrypt_module_close. Deszyfrowanie
SHA1 X  sha1( ), sha1_file( ) X  MHASH_SHA1
informacji przebiega niemal analogicznie,
SHA256 X  MHASH_SHA256
z tą różnicą, że zamiast funkcji mcrypt_
TIGER X  MHASH_TIGER
generic stosujemy mdecrypt_generic,
TIGER128 X  MHASH_TIGER128
która przyjmuje identyczne argumenty co
TIGER160 X  MHASH_TIGER160 poprzednia.
Aby zainicjować mechanizmy bi- frowania wraz z opisem umieszczone zo- Bezpieczna składnica danych
blioteki Mcrypt, musimy wywołać funk- stały w Tabeli 3. Wynik działania omawia- Posiadając już niezbędną wiedzę na te-
cję mcrypt_module_open, która jako pierw- nej funkcji zapisujemy w zmiennej pomoc- mat wykorzystania biblioteki MCrypt, na-
szy argument przyjmuje nazwę algoryt- niczej $td. Kolejnym krokiem jest utworze- piszmy odpowiednie funkcje do naszej
mu, z którego chcemy skorzystać. Drugi nie za pomocą funkcji mcrypt_create_iv aplikacji. Kod zródłowy skryptu szyfrują-
i czwarty parametr to ścieżki do odpowied- tzw. wektora inicjującego. Funkcja ta cego przesyłany plik przedstawiony jest
nich modułów, pozwalających na skorzy- wymaga podania rozmiaru wektora oraz na Listingu 9.
stanie z danego algorytmu. Pozostawienie zródła danych losowych. Najlepiej skorzy- Przed dodaniem rekordu do tabe-
ich pustych, jak w przykładzie, powodu- stać ze stałej MCRYPT_RAND, ponieważ spo- li sprawdzamy czy użytkownik podał
je wykorzystanie ścieżek zdefiniowanych sób ten działa zarówno pod systemem wymagany klucz oraz czy sam plik został
w pliku konfiguracyjnym php.ini. Trzeci ar- Linux jak i Windows. W tym miejscu bi- pomyślnie przesłany na serwer. Następ-
gument definiuje tryb, w jakim ma odby- blioteka MCrypt jest gotowa na przyjęcie nie tworzymy skrót klucza wykorzystując
wać się szyfrowanie  my skorzystamy danych do zaszyfrowania. Najpierw musi- algorytm MD5, aby pózniej przy pobie-
z trybu ecb. Wszystkie możliwe tryby szy- my zarezerwować odpowiednią ilość miej- raniu pliku móc szybko zweryfikować je-
go prawidłowość. Unikniemy tym samym
sytuacji, gdy ktoś ściągnie plik, po czym
okaże się, że pomylił klucze, a ściągnięty
plik jest bezużyteczny. Po odczytaniu pliku
szyfrujemy jego zawartość i dodajemy od-
powiedni wpis do bazy danych.
Zobaczmy, jak wygląda funkcja
pobierania wcześniej dodanych plików.
Instalacja rozszerzenia
MCrypt
Jeżeli posiadasz system Windows, mu-
sisz posiadać plik libmcrypt.dll do-
stępny do pobrania ze strony http://
ftp.emini.dk/pub/php/win32/mcrypt/,
a następnie umieścić go w katalogu c:
\windows\system32\. Posiadacze innych
systemów powinni odwiedzić stronę http://
mcrypt.sourceforge.net/ i pobrać zródła
biblioteki, a następnie je skompilować.
Aby korzystać z rozszerzenia MCrypt
w PHP, musimy go skompilować z dyrek-
tywą -with-mcrypt[=DIR] gdzie DIR to
ścieżka do biblioteki libmcrypt.
Rysunek 2. Strona domowa rozszerzenia MCrypt dla PHP (http://php.net/mcrypt)
PHP Solutions Nr 4/2006 www.phpsolmag.org
39
Bezpieczeństwo Kryptografia w PHP
Tabela 2. Najpopularniejsze algorytmy szyfrowania dostępne w rozszerzeniu MCrypt Najpierw dokonujemy porównania klu-
cza nadesłanego przez użytkownika
Nazwa stałej Algorytm Rozmiar Rozmiar
z tym przypisanym do danego pliku. Jeśli
klucza bloku
klucze (a w praktyce ich skróty MD5) są
MCRYPT_3DES Potrójny DES 168 64
identyczne możemy rozszyfrować zwar-
MCRYPT_THREEWAY 3way 96 96
tość pliku. Cały ten proces nie różni się
MCRYPT_BLOWFISH Blowfish do 448 64
znacznie od zwykłego szyfrowania i został
MCRYPT_CRYPT Szyfrowanie unikowe 104 8
już wcześniej zaprezentowany. Ponieważ
MCRYPT_DES DES 56 64 użytkownik ma mieć możliwość zapisania
pliku na swój dysk, koniecznie staje się
MCRYPT_GOST Sowiet Gosudarswiennyj 256 64
wysłanie odpowiednich nagłówków do je-
MCRYPT_IDEA International Data Encryption 128 64
go przeglądarki. Wykorzystamy do tego
Algorithm
funkcję header oraz nagłówki Content-
MCRYPT_SERPENT Serpent 128, 192 128
Type i Content-Disposition. Na koniec,
lub 256
jeszcze przed wysłaniem zawartości pliku,
MCRYPT_TWOFISH Twofish 128, 192 128
musimy usunąć ewentualne puste znaki,
lub 256
które funkcje szyfrujące mogły pozostawić
na końcu pliku, a które mogłoby spowodo-
Listing 8. Przykład wykorzystania rozszerzenia MCrypt
wać pózniejsze błędy w jego odczycie. Ja-
ko że znamy długość oryginalnego pliku
(została zapisana w bazie danych), może-
// Nasz klucz i łańcuch znaków do zaszyfrowania
$key = 'tajny klucz'; my to bez problemu wykonać przy użyciu
$plain_text = 'bardzo poufne dane, które trzeba zaszyfrować';
funkcji substr.
// Inicjacja mechanizmów szyfrujących
Przedstawiony przykład pokazał,
$td = mcrypt_module_open('blowfish', '', 'ecb', '');
jak szybko możemy zaszyfrować nasze
$key = substr($key, 0, mcrypt_enc_get_key_size($td));
dane i jak przechowywać je w bazie.
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
// Szyfrowanie Mogą to być zarówno hasła jak i zawar-
mcrypt_generic_init($td, $key, $iv);
tości całych plików. Pamiętajmy jednak,
$encrypted = mcrypt_generic($td, $plain_text);
że proces szyfrowania 40MB pliku mo-
mcrypt_generic_deinit($td);
że dość znacznie obciążyć procesor,
echo $encrypted;
a także spowodować przepełnienie pa-
// Deszyfrowanie
mcrypt_generic_init($td, $key, $iv); mięci przydzielonej dla PHP, co w efek-
$decrypted = mdecrypt_generic($td, $encrypted);
cie spowoduje wyświetlenie komuni-
mcrypt_generic_deinit($td);
echo $decrypted;
mcrypt_module_close($td);
?>
O autorach
Listing 9. Skrypt szyfrujący przesłany plik
Aukasz Lach studiuje informatykę na
wydziale Cybernetyki Wojskowej Aka-
$file = $_FILES['file'];
demii Technicznej w Warszawie. Od
if($file['error'] == UPLOAD_ERR_OK && !empty($_POST['key']))
{ kilku lat zajmuje się tworzeniem apli-
if(!empty($_POST['name']))
kacji internetowych z wykorzystaniem
$file['name'] = $_POST['name'];
takich technologii jak PHP, XHTML,
$key = md5($_POST['key']);
JavaScript czy XML. Posiada certyfi-
$data = file_get_contents($file['tmp_name']);
kat Zend Certified Engineer. Jest au-
$td = mcrypt_module_open('des', '', 'ecb', '');
$subkey = substr($key, 0, mcrypt_enc_get_key_size($td)); torem licznych publikacji prasowych
$iv_size = mcrypt_enc_get_iv_size($td);
w czasopismach polskich i zagra-
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
nicznych na temat tworzenia aplikacji
mcrypt_generic_init($td, $subkey, $iv);
internetowych i bezpiecznym progra-
$encrypted_data = mcrypt_generic($td, $data);
mowaniu w PHP.
mcrypt_generic_deinit($td);
mcrypt_module_close($td); Michał Stanowski opanował
mysql_query("INSERT INTO 'secure_files' ('name', 'mime_type', 'date',
w stopniu zaawansowanym umiejęt-
'length', 'key', 'data')
ność obiektowego tworzenia aplikacji
VALUES ('{$file['name']}', '{$file['type']}', UNIX_TIMESTAMP(),
w PHP5. Interesuje się bezpieczeń-
'{$file['size']}', '$key', '".mysql_real_escape_string
stwem aplikacji internetowych oraz ich
($encrypted_data)."')") or die(mysql_error());
} użytecznością. Swój wolny czas spę-
?>
dza zwiedzając Polskę na rowerze.
www.phpsolmag.org PHP Solutions Nr 4/2006
40
Kryptografia w PHP Bezpieczeństwo
Tabela 3. Tryby szyfrowania wspierane przez rozszerzenie
MCrypt
Nazwa stałej Opis
MCRYPT_MODE_ECB Tryb książek elektronicznych
MCRYPT_MODE_CBC Tryb łańcuchowego łączenia blo-
ków
MCRYPT_MODE_CFB Tryb sprzężenia zwrotnego szy-
frowania
MCRYPT_MODE_OFB Tryb sprzężenia zwrotnego wyj-
ścia z 8 bitami sprzężenia
MCRYPT_MODE_NOFB Tryb sprzężenia zwrotnego wyj-
ścia z liczbą bitów sprzężenia
równą rozmiarowi bloku algo-
rytmu
MCRYPT_MODE_STREAM Tryb szyfrowania strumienio-
wego
Rysunek 3. Aplikacja bezpiecznego przechowywania plików na
serwerze w postaci zaszyfrowanej
katu o błędzie i zakończenie działania skryptu. Wydłużenie
czasu szyfrowania może być również spowodowane wybra-
niem algorytmu o dużej złożoności obliczeniowej. Dobrym
rozwiązaniem jest w tym wypadku szyfrowanie pojedynczych
bloków danych. O tym, jak duży może być blok dla danego
algorytmu szyfrującego, informuje nas funkcja mcrypt_get_
block_size lub mcrypt_enc_get_block_size.
Podsumowanie
W artykule przedstawiliśmy tylko część możliwości funkcji
kryptograficznych, jakie możemy zastosować w aplikacjach
PHP. Nasze przykłady pokazały Wam, jak zabezpieczać da-
ne czy tworzyć bezpieczne systemy uwierzytelniania. W ko-
lejnych artykułach opowiemy m.in. o wykorzystaniu bibliote-
ki OpenSSL oraz wysyłaniu bezpiecznych emaili z poziomu
PHP. n
PHP Solutions Nr 4/2006
41


Wyszukiwarka

Podobne podstrony:
2006 06 RSA w PHP chronimy nasze dane przy użyciu kryptografii asymetrycznej [Kryptografia]
2006 04 Karty produktów
2006 04 Get the Spin
2006 04 Klucz do wlasnej firmy
2006 04 Piszemy widget zegara w GTK [Programowanie]
2006 04 O diagnostyce i terapii bólów krzyża
2006 04 11 Uchwała ZG OSP system szkoleniaid 456
SIMR MAT1 EGZ 2006 04 20 rozw
2006 04 Stół rehabilitacyjny HIFLY
2006 04 O profilaktyce zdrowia pracowników
2006 04 Images of the Empire Msn Messenger in Linux with Webcam Support
2006 04 Trzy kolory TLK MED u
2006 04 Medycyna oparta na faktach
2006 04 GIMP w praktyce [Grafika]

więcej podobnych podstron