C, PHP, VB, .NET

Дневникът на Филип Петров


* PHP handlers

Публикувано на 19 януари 2013 в раздел ОСУП.

За да може да пуснете сайт на PHP, уеб сървъра ви трябва да може да компилира всичко, което е оградено с тагове . PHP handler е модул за HTTP сървъра, който зарежда библиотеките на PHP. Специално за Apache съществуват няколко различни PHP handlers. Изборът на един или друг предопределя различни аспекти като бързина, заета памет и сигурност. Нека разгледаме най-популярните.

mod_php – PHP като модул на Apache

Този handler е стандартния за PHP. Истинското му име е Dynamic Shared Object, но е по-познат като mod_php. При него PHP се зарежда като модул вътре в самото Apache. Един недостатък на този модул е, че при споделените хостинг услуги (много потребители на един сървър) е трудно да се определи кой от потребителите на сървъра изпълнява PHP кода, защото той ще се изпълнява с потребител „nobody“ (при някои системи с „apache“). Огромният недостатък е, че всички файлове, които се генерират от самото PHP, ще са с owner „nobody“, а не на потребителя. Това прави невъзможно те да са директно видими в уеб. Алтернативата е файловете да са с привилегии 777, за да може Apache да има права за писане върху тях. И в двата случая обаче това е основен проблем при многопотребителските системи, защото става теоретически възможно един потребител да навреди на файлове на друг (ако user1 има файлове със собственик „nobody“ или с привилегии 777, то user2 би могъл да ги достъпва и модифицира чрез свои скриптове). Това прави mod_php силно непрепоръчителен за споделен хостинг. Този голям недостатък обаче може да бъде приет и като предимство за системи, които работят само с един потребител с един уеб сайт. В този случай може системата да се конфигурира така, че файловете да се качват със собственик user и по този начин процесът на Apache няма да има права да ги променя, т.е. дори да имате компрометиран скрипт, той няма да може да навреди на нищо друго, освен на файлове създавани от „nobody“ или „Apache“ (или файлове с права 777). Има възможности за допълнително „замаскиране на проблема“ с потенциалния достъп на едни потрепители до файлове на други, като се включват настройки като „safe mode“ (в по-новите версии на PHP ще отпадне) или open_basedir (забрана за „връщане назад“ в директориите).

Някои приложения (например WordPress) заобикалят проблемите с „nouser“, като използват модули за осъществяване на FTP връзка през PHP. Други складират файловете в бази от данни. Често ще видите при някои приложения и директни указания като например „сменете правата на директория attachments на 777“ и подобни ръчни решения.

mod_cgi – PHP като стандартен CGI модул

CGI модул в случая най-просто казано означава, че Apache ще се свърже с отделна програма (приемете го като PHP компилатор), която ще приеме сорс кода, ще го компилира и ще върне обратно готов резултат. Този модул всъщност е най-елементарния CGI вариант на PHP. Ако няма допълнително наличен suEXEC модул на Apache, скриптовете ще се пускат с потребител „nobody“. При наличие на suEXEC, всеки скрипт ще се изпълнява със потребител собственика на скрипта. За всяка заявка се стартира нов процес, който връща отговор и се затваря. Недостатъкът е очевиден – този процес на взаимодействие е по-бавен, отколкото ако процесът на Apache вършеше работата самостоятелно. Голямо предимство от гледна точка на сигурността в многопотребителски системи е, че става възможно скриптовете да се изпълняват с потребителя, който е техен собственик. Това е особено важно, понеже един компрометиран скрипт не би могъл да навреди на скриптове на други потребители.

Липсата на възможност един потребител да навреди на друг е нещо много добро за многопотребителските системи, но от друга страна изпълнението на скриптове с потребителския акаунт може да доведе до много по-сериозни поражения за самия него. Компрометиран скрипт би могъл да достъпи всякакви други ресурси (извън контролираните от уеб сървъра) за този потребител – файловете с качените с неговия потребител скриптове, електронна поща, системни файлове и др. При mod_php това не е така, защото PHP скриптовете ще работят с „Apache“, а не с името на потребителя. От тази гледна точка е важно да се отбележи, че е заблуда да се каже категорично, че „работата със CGI е по-сигурна от работата с mod_php“. Тук сигурността е от съвсем различни аспекти. CGI осигурява по-висока сигурност за многопотребителска система (администраторите могат да бъдат спокойни, че ако един потребител бъде хакнат, то последиците ще са само и единствено за него), но за сметка на това хакването на един сайт би могло да доведе до „пълна щета“ за него (подмяна на основни файлове, кражба на информация и т.н.).

Често като недостатък за mod_cgi (както и всички различни от mod_php) е невъзможността да се правят динамични настройки на конфигурацията на PHP чрез .htaccess файл (php_flag директивите не работят). Като алтернатива някои хостинг компании предоставят възможност всеки един от клиентите да има самостоятелен php.ini файл. Има и допълнителeн модул наречен „Htscanner“, който разрешава този проблем.

suPHP – комбинация между Apache модул и CGI

suPHP е популярна и доста добра алтернатива на mod_cgi + suEXEC. При него работата е разделена – част от управлението е модул на Apache (mod_suphp), а друга част е setuid root изпълнимо приложение (suphp), което се извиква от Apache, за да се смени uid на процеса, който стартира PHP скрипта. Подобрението в бързодействието спрямо mod_cgi се оказва незначително, но практиката досега показва, че работата със suPHP е значително по-стабилна и по-лесна за управление. Поради тази причина suPHP се превърна в предпочитан избор за администраторите спрямо mod_cgi+suEXEC. При suPHP НЕ могат да се използват оптимизатори като APC и eAccelerator. Поддържа се „per user“ php.ini конфигурационен файл.

FastCGI – PHP като CGI модул с поддържане на постоянна връзка

FastCGI e популярното име на разширението mod_fcgi. Практически той има всички качества на mod_cgi (и допълнителни, като например поддръжката на APC или eAccelerator оптимизатори), но заема значително по-малко процесорно време (тестовете показват, че често се доближава по скорост към mod_php). Оптимизацията е постигната, като процесите и нишките се пазят живи (в спящ режим) дори след завършването на работата си, вместо да бъдат затваряни и отваряни непрекъснато за всяко парче код както става при mod_cgi (и при suPHP, където за всяка заявка се извиква приложението suphp). Това разбира се си има цена – значително увеличено потребление на заета оперативна памет.

PHP-FPM – Алтернатива на FastCGI

FPM е съкращение от „FastCGI Process Manager“. Както името му подсказва, основната идея, на която се стъпва е да се държат процесите и нишките активни, но и добавя „менажер на процеси“. Разликата спрямо FastCGI е, че при PHP-FPM процесите и нишките се менажират не от уеб сървъра (Apache), а от daemon, който работи паралелно с него (с други думи въвсем самостоятелна програма – PHP сървър). В него е добавена функционалност за следене на статистики (натоварване на процесора, свободна оперативна памет, трафик и др.), които от своя страна служат за „динамично скалиране“ на системата. Казано по друг начин – PHP-FPM се самооптимизира спрямо статистиките, които събира. В конфигурацията се задават минимални ресурси, които трябва задължително да бъдат заделени, както и максимални ресурси, които могат да бъдат заети. Ако този максимум бъде достигнат, PHP-FPM ще започне да изключва спящи процеси и нишки. Обратно – ако PHP-FPM забележи, че трафика на сайта ви се увеличава, той автоматично ще стартира допълнителни child процеси, които да обслужват новите заявки към него. По принцип уеб сървърът Apache също извършва подобни оптимизации, но в случая PHP-FPM ги прави специфично за PHP, т.е. се смята (и засега практически се доказва), че ги прави по-добре. Работата с PHP-FPM е по-бърза от suPHP, по-гъвкава (но малко по-бавна) от FastCGI, но продължава да бъде значително по-бавна от mod_php. При всички положения е по-добър избор от FastCGI, защото се спрявя значително по-добре с обработването на множество паралелни заявки.

mod_php + mod_ruid2

С Apache 2.2 се появи и модула mod_ruid2. С него става възможно да използвате mod_php, но същевременно с това да изпълнявате скрипта чрез потребителя на домейна (подобно на всички останали варианти). Apache стартира child процеси със своя потребител, които първоначално са в спящ режим. Когато дойде заявка, Apache я предава на съответен свободен child процес и променя потребителя му. Когато процеса свърши работата си, потребителя отново се сменя обратно на „Apache“. Това напълно премахва недостатъка за потребител „nobody“ на mod_php и реално системата започва да работи сходно с принципа на действие на suPHP, но по-бързо, защото не се извиква външно приложение. Освен това е възможно да се използват оптимизатори като APC и eAccelerator. За да може да бъдат променяни потребителите обаче e нужно основния процес на Apache се пуска с потребител root (така child процесите се променят от него). Самите разработчици отчитат това като възможен сериозен пробив в сигурността, защото ако самият процес на Apache бъде компрометиран, тогава ще е възможно да се смени потребителя на скрипта да бъде root, а от там хакера ще има достъп до цялата система. Тоест за разлика от другите решения, където уеб сървъра винаги работеше със свой собствен потребител, тук правата на достъп на самия сървър са сериозно повишени. Също така трябва да се отбележи, че mod_ruid2 не работи по BSD базирани системи.

Обновено юни 2017 г.

В последните години нещата леко се промениха с появата на HTTP2. При него се изисква и очаква многонишковост при http сървъра. Ако се фокусираме върху Apache, това зависи от т.нар. „Multi-Processing Modules“ (MPM), с който е компилиран. Разпространените режими са три:

  1. Prefork – за всяка нова връзка се отваря отделен Apache процес. Няма многонишковост на сървъра;
  2. Worker – процесите отварят нишки, които могат да обработват допълнителни заявки от потребителите;
  3. Event – същото като Worker, но т.нар. „keep alive“ заявки се прехвърлят към отделен многонишков процес, който е оптимизиран да работи с тях.

Понеже http2 предполага именно многозадачност (множество заявки да се обработват с една единствена tcp/ip връзка), то Prefork се явява напълно неподходящ режим за работа. Теоретично е възможно да работи, но се губят всички предимства на новия протокол. Затова в Apache 2.4.27 поддръжката на http2 с prefork отпада.

Това дава отражение и в режимите, в които работи PHP. Попринцип mod_php и mod_php + mod_ruid2 работят в режим prefork, т.е. стават несъвместими с http2. При SuPHP, FastCGI и PHP-FPM няма проблем да се използва Event или Worker режим.

 



Добави коментар

Адресът на електронната поща няма да се публикува


*