PHP: Как да накараме бот да ни счупи сайта?

Posted by Асен on June 11th, 2009

Днес видях нещо което ме изуми! Един обикновен идексиращ бот (на търсеща машина) затри съдържанието на цял сайт, докато се е опитвал да индексира админ панела, при това без да вижда какво има вътре тъй като има логин система за администраторите. И всичко това заради малък пропуск в php кода.

Ето и по-дългият вариант на историята.

Един клиент ми се обади и се оплака, че сайта му е хакнат. Аз гледам, няма нищо в базата данни от съдържанието на сайта. В лога на сървъра се вижда как един бот се е опитвал да влезе в админ панела, но е получавал 302 редирект към страницата за вход. Никой друг не се е опитвал да влезе.

Какво се е случило на този далечен сървър???

След кратко разсъждение стана ясно, че има двама виновници. Първият е програмиста който е писал системата, а вторият е собственика на сайта който просто е инсталирал toolbar на търсеща машина на браузера си.

Проблема в кода може би може да бъде срещнат в повечето сайтове написани на php. Ето го и въпросното бъгче:

if (!isset($_SESSION['Admin'])){
header(“location:login.php”);
}

Тук голяма роля играе и настройката на сървъра, но тъй като това е известен проблем програмиста е трябвало да го съобрази.

Във въпросния код функцията header() казва на браузера  да се пренасочи към страницата за вход, но не казва на сървъра да спре изпълнението на текущата страница. Т.е. ако аз нямам права да изтрия дадена статия (например), но имам адреса чрез който може да се изтрие, след като го посетя ще видя страницата искаща парола, но сървъра ще изпълни и изтриването. Гадно а?

А как бота е разбрал адресите които трябва да се посетят за изтриване на съдържание от сайта? Отговора е още по-смешен и от php кода. Администратора, който има инсталиран toolbar на търсещата машина, без да знае е дал тези адреси на бота, като е влезнал да администрира сайта си.

Това отново повдига в съзнанието ми въпроса колко лична информация събират големите търсачки за нас, без дори да се замислим, че сме им позволили.

Извода за програмиста (който вероятно няма и да разбере какво е направил) е, че трябва да окаже на съвръра да спре да изпълнява команди ако има пренасочване, ето така:

if (!isset($_SESSION['Admin'])){
header(“location:login.php”);
exit(0);
}

Също така да се научи да използва robots.txt.

Извода за клиента е, че е по-добре да плати веднъж много пари за стабилен софтуер, отколкото да мине тънко и да го хакне тарсачка, преди да реши да даде много пари за отстраняването на проблема :D

Как да пишем по-добър PHP код

Posted by Асен on November 30th, 2008

Провокиран от блога на един колега, реших да напиша моите виждания над това, как е най-добре да бъде написан един сайт на php.

  • Не използвайте framework-ове - ако питате мен това си е смъртен грях. Да се инклудне такова огромно количество код, само защото програмиста не знае как да си реализира сам решението на задачата си, е направо истинско мъчение за всеки сървър.Не ме разбирайте погрешно, Аз харесвам някои framework-ове, но те винаги реализират много сложни неща и спестяват на програмиста много дни/седмици/месеци работа. Пример за php такъв не мога да дам, защото не съм използвал, но за JavaScript имам добри впечатления от ExtJs.

    Тези които използват framework за да се свържат към базата данни, или каквото и да нормално нещо изискващо 10-15 реда код да се напише (например функции за свързване/изпращане на заявки към база данни), според мен не са php програмисти, защото ако трябва да напишат нещо без framework-а ще го направят по-зле от кучето ми.

    Знам че има хора които просто спестяват 4 мин. работа за тях за сметка на сървъра, и всъщност могат да си го напишат сами на php, така че тук направих голяма генерализация.

    И все пак, по-добър код е този специално написан за даденото приложение, а не framework направен да работи във всяка ситуация, независимо колко знания има използващия го.
  • Не използвайте register_globals и magic_quotes – Има ли нужда от коментар? Много по-добре е да работите без подобни екстри от страна на сървъра. Използването им води до огромни дупки в сигурността, а до някаква степен и натоварва повече сървъра.

    Радвам се че в PHP 6 тези двете ще бъдат премахнати. По-този начин броят на некадърните програмисти би трябвало да намалее. Презирам дори хостове които ги държат включени по подразбиране ;)
  • Отваряйте по една връзка към базата данни – Не мислех че ще се наложи да напиша толкова интуитивно нещо, но напоследък виждам голяма част колеги, които явно от незнание, но се оказва че имат 10-15 връзки към базата по едно и също време от един скрипт. Без коментар!

    Също така е добре да затворите връзката към базата данни ако сте приключили с нея по-рано отколкото ще завърши скрипта ви.
  • Не извиквайте функции в тялото на цикъл – Освен ако не е наложително разбира се. Добър програмист не би трябвало да пише код от рода на:
    for($i=0;$i<count($arr);$i++)
    особено когато има толкова по приятен вариант:
    $arr_len=count($arr);
    for($i=0;$i<$arr_len;$i++)

    Това е често срещан случай, но същото се отнася и за извиквани на функция в while и каквото и да е друго нещо, което ще се изпълни много пъти. Ако е възможно извикването трябва да се извърши преди цикъла.
  • Заграждайте стринговете с единични кавички – При използването на двойни кавички php търси дали в стринга няма променливи които трябва да постави. Това е много бавен процес. Винаги затваряйте стринга с единични кавички и го прекъсвайте когато трябва да включите променлива.

  • Когато достъпвате елемент от масив с ключ стринг, винаги го заграждайте в единични кавички – Имам в предвид, че $arr[key] е няколко пъти по-лош вариант от $arr['key']. Второто е около 7 пъти по-бързо. Разбира се ако имате числов индекс не го заграждайте.
  • Не използвайте операторе за подтискане на грешки - Много бавно и тежко решение да прикриете зле написан код. По-добре го пренапишете без грешки. В малък процент от случаите @ е полезен оператор.
  • Използвайте echo с няколко параметъра – Вместо да напишете нещо от рода на
    echo $x.’ plus ‘.$y.’ equals ‘.($x_$y);
    Можете да го напишете така:
    echo $x,’ plus ‘,$y,’ equals ‘,($x_$y);

    Това което се случва тук е, че в първият вариант свързвате няколко стринга и тогава ги изпращате на функцията echo, а във втория извиквате echo с няколко параметъра и избягвате свързването на стринга. Това е доста по-бърз вариант да се направи същото нещо.

    Това поведение е валидно само за функцията echo.

  • Използвайте isset() вместо strlen() – Това на много места е казвано. isset() може да се използва много умно и да направи кода ви по-бърз на много места.
  • Избягвайте require_once() и include_once() – Следенето дали даден файл вече е бил инклуднат невинаги е цена която си заслужава да се плати. По добре напишете така кода, че винаги да се инклудва веднъж. Разбира се понякога е невъзможно или прекалено трудно.
  • Избягвайте регулярни изрази – Когато можете да направите нещо без регулярен израз е по добре да го направите така. Избягвайте функции очакващи регулярни изрази като split и ги заменяйте с по-бързите им алтернативи.
  • Използвайте вградените функции на php – Ако има вградена функция която прави това което прави и вашата, по добре е да използвате вградената. Има голяма вероятност вградената да го прави по-ефективно.
  • Декларирайте променлива преди да я използвате – Може да не се вижда, но използването на недекларирана променлива е доста по бавно от варианта в който я декларирате преди да я използвате.
  • ++$i и –$i са по-бързи от $i++ и $i– – Това е така защото вторите, освен че увеличават с едно, запазват старата стойност за да я върнат. Ако знаете какво правят тези оператори ще се досетите защо първите са по-бързи.
  • Не разделяйте кода си на прекалено много функции - Освен ако наистина имате код който ще използвате на много места, разделянето му във функции е безсмислено. Извикването на една функция отнема време колкото 7-8 инкрементации. (само извикването, изпълнанието на е включено ;) )
  • Използвайте ООП умерено – Забелязвам че по-неопитните колеги като научат какво е ООП го използват навсякъде, т.е. където не трябва. Добре е да се знае, че използването ООП не е предимство, освен ако не се решават важни въпроси които не могат да станат по-добре в процедурен стил.

    Извикването на метод на обект е 3 пъти по-бавно от извикването на обикновена функция. Сега си представете какво става при наследяване, защото извикването на метод от базов клас е по-бавно от извикването на метод от производния клас.

Това са част от нещата които се старая да спазвам на продуктивни сайтове. Ако смятате че греша не се колебайте да ме поправите, но по-добре да знаете какво говорите ;)


Copyright © 2012 Асен Сотиров, ДевСпел ООД
Theme by Correos masivos