Много често уеб приложенията стават жертва на SQL инжекции, които помагат на злодеятелите да се сдобият с цялата база от данни на приложението. В тези случаи, цялата информация на потребителите, като имена и пароли, се указва в ръцете на престъпници. Много хора ползват една и съща парола за всички онлайн услуги. Затова трябва да попречим на злодеите да прочетат свободно тази информация. Един от начините за постигане на това е чрез хеширане на паролите на потребителите.
Стандартно, в PHP, хеширането се прави с md5 или sha1. Тук може да намерите кратка статия за това, как се ползват двете функции в PHP.
Защо не харесвам това решение? Това са алгоритми, които математически са проектирани с друга цел. Това са шехиращи функции, с общо предназначение, които могат да сметнат шехове на голямо количество данни – бързо. Те са прекрасни за проверка на интегритета на данни, но са кофти решение за хеширане на пароли. Един средно нов компютър, може да смята хеш на 330MB за секунда. Ако вашите потребители имат пароли от 6 символа, с малки букви, които съдържат само букви и цифри(каквито са паролите на обикновените хора), може да пресметнете абсолютно всички възможни комбинации за 40 секунди. Ако похарчите 2000 долара и си поиграете малко с CUDA може да си направите личен малък суперкомпютър, който да пробва 700 000 000 пароли за секунда. Така ще краквате слабите пароли само за секунда. Подобен начин за налучкване на парола, чрез пробване на всички възможни комбинации, се нарича атака с груба сила.
В статията която ви показах горе се споменава за „сол“ или salt. Защо „соленето“ на пароли не ни помага? То е просто безполезно, за защита от атаки с група сила. Дори и да ползвате голяма „сол“ или много на брой „сол“-и или да използвате морска кристална сол от Черноморски солници АД Бургас, пак няма да ви помогне. Просто не указва влияние на времето, за което човек може да опита всички пароли, като има шехирания вариант и вашия „сол“(било то от сорса или от базата от данни).
А как трябва да се направи? Единия вариант е като ползваме sha512, с индивидуална „сол“ за всеки потребител и stretching(английски) на паролите. Сега ще разгледаме всяка една от думичките по отделно. Първо, sha512 е алгоритъм за хеширане, от фамилия SHA-2. Той използва големи 64 битови думи. Това го прави по-труден за налучкване. За да използваме този алгоритъм в PHP извикваме функцията hash с параметър ‘sha512′. От версия 5.1.2, тази функция е част от стандартните функции в PHP и няма нужда от допълнителна инсталация. Друго, което предприемаме е ползване на „сол“, която се генерира уникално за всеки потребител. Последното нещо, което правим е stretching. Това е техника, която цели да направи лесни за отгатване данни(като паролите) – трудни за отгатване. При нея, итеративно, се подава на хеш функция конкатенация от солта, паролата и хеша, получен на предишната итерация. Това се прави достатъчен брой пъти: Избирате си едно число в интервала [200ms, 1000ms] и го разделяте на времето, което отнема едно изпълнение на цикъла на вашият хардуер. Полученото число записвате в константата LIMIT.
Ето го и примера:
function securePassword($password, $salt) { $hash = ''; for ($i = 0; $i < LIMIT; $i++) { $hash = hash('sha512', $hash.$salt.$password); } return substr(base64_encode($salt), 0, 22). $hash); }
А ето как проверяваме, дали паролата е валидна:
function validPassword($password, $hash) { $salt = substr($hash, 0, 22); $newHash = ''; for ($i = 0; $i < LIMIT; $i++) { $newHash = $hash('sha512', $newHash.$salt.$password); } return ($salt.$newHash == $hash); }
И пак мога да ви атакуват с груба сила.
По-доброто решение. Може да ползвате bcrypt(английски). Това е изключителен алгоритъм, проектиран специално за хеширане на пароли. Включва в себе си "сол" за защита от rainbow table атаки. Също така е адаптивен хеш: може да става по-бавен с времето и така да предпази от атаки с груба сила.
В PHP, може да го ползваме, чрез функцията crypt. Ето как изглежда цялата магия:
$salt = substr(str_replace('+', '.', base64_encode($salt)), 0, 22); $hash = crypt($password, '$2a$'.$cost.'$'.$salt);
$cost си го избирате, като число в интервала [4, 31], в зависимост от скоростта на вашия хардуер. Ако числото, което си изберете е едноцифрено, го запишете с нула отпред. Пример - 01, 02, 03, 04... 09.
'$2a$'.$cost.'$' е седем битова заглавна част, която показва на crypt че искаме да ползваме bcrypt
А така проверяваме дали паролата е коректна:
$hash == crypt($password, $hash);
Ако искаш да хешираш нещо бързо и просто, тогава ползваш алгоритъм за тази цел. Ако искаш да пазиш пароли, ползваш алгоритъм за хеширане на пароли. Това е идеята.
А относно md5, при 700 000 000 пароли за секунда, колко време ми трябва да попадна на хеша със сложния стринг вътре? „Солта“ не спасява от brute force.
23:36
Всичко това е много хубаво, но много често се налага да се ползва нещо бързо, лесно и просто. Например за информация, която не е парола, но трябва да се хешира и дори може да бъде публично достъпна (тоест хеша се вижда не само чрез SQL инжекция).
За да може реалната стойност да е скрита е достатъчно да се направи md5 като към информацията, която скриваме добавим наш сложеш стринг с всякакви типове знаци, за да предовратим изпълнение на brute force по начина по който го описа.