HTTP server se separací práv

Podobné dokumenty
A p a c h e h t t p d Lukáš Zapletal lukas.zapletal@liberix.cz

Instalace a konfigurace web serveru. WA1 Martin Klíma

Od CGI k FastCGI. Uvedené dílo podléhá licenci Creative Commons Uved te autora 3.0 Česko.

Vlákno (anglicky: thread) v informatice označuje vlákno výpočtu neboli samostatný výpočetní tok, tedy posloupnost po sobě jdoucích operací.

HTTP protokol. Zpracoval : Petr Novotný

Internet Information Services (IIS) 6.0

Užitečné odkazy:

Použití programu WinProxy

Architektura rodiny operačních systémů Windows NT Mgr. Josef Horálek

Současný svět Projekt č. CZ.2.17/3.1.00/32038, podpořený Evropským sociálním fondem v rámci Operačního programu Praha adaptabilita

Protokol HTTP 4IZ228 tvorba webových stránek a aplikací

2015 GEOVAP, spol. s r. o. Všechna práva vyhrazena.

Procesy a vlákna (Processes and Threads)

Úvod do informačních služeb Internetu

Olga Rudikova 2. ročník APIN

PHP PHP je skriptovací programovací jazyk dynamických internetových stránek PHP je nezávislý na platformě

MATLABLINK - VZDÁLENÉ OVLÁDÁNÍ A MONITOROVÁNÍ TECHNOLOGICKÝCH PROCESŮ

PHP a bezpečnost. nejen veřejná

PHP framework Nette. Kapitola Úvod. 1.2 Architektura Nette

BI-AWD. Administrace Webového a Databázového serveru Instalace webového serveru Apache httpd

Přednáška. Vstup/Výstup. Katedra počítačových systémů FIT, České vysoké učení technické v Praze Jan Trdlička, 2012

Implementace systémů HIPS: historie a současnost. Martin Dráb

Obsah. Předmluva Kapitola 1 Úvod 1. Web v kostce 1 Kdo je webmaster? 4 Doporučená literatura 4. Kapitola 2 Přehled jazyka HTML 5

Microsoft SharePoint Portal Server Zvýšená týmová produktivita a úspora času při správě dokumentů ve společnosti Makro Cash & Carry ČR

1 Uživatelská dokumentace

rychlý vývoj webových aplikací nezávislých na platformě Jiří Kosek

Ročníkový projekt DYNAMICKÉ HTML. Projektová dokumentace. Jan Ehrlich, Petr Marek, Tomáš Marván, Martin Paľo. Vedoucí projektu: RNDr.

Služba ve Windows. Služba (service) je program

INSTALACE PRODUKTU ONTOPIA KNOWLEDGE SUITE

Technická specifikace

1 Webový server, instalace PHP a MySQL 13

Real Time programování v LabView. Ing. Martin Bušek, Ph.D.

monolitická vrstvená virtuální počítač / stroj modulární struktura Klient server struktura

BI-AWD. Administrace Webového a Databázového serveru Rozšiřující moduly serveru Apache httpd

1 Správce licencí Správce licencí Správce licencí Start > Všechny programy > IDEA StatiCa > Správce licencí Soubor > Správce licencí Licence

úvod Historie operačních systémů

ČESKÉ VYSOKÉ UČENÍ TECHNIKÉ Fakulta elektrotechnická. Microsoft Sharepoint 2007 Workflows Průmyslové informační systémy

Pánem World Wide Webu! aneb povídání o chybě hloupé tak, až to bolí

Správa zařízení Scan Station Pro 550 a Servisní nástroje zařízení Scan Station

plussystem Příručka k instalaci systému

Instalace a první spuštění Programu Job Abacus Pro

Registrační číslo projektu: CZ.1.07/1.5.00/ Elektronická podpora zkvalitnění výuky CZ.1.07 Vzděláním pro konkurenceschopnost

Ope p r e a r čn č í s ys y té t m é y y Windo d w o s Stručný přehled

Provádí ochranu sítě před napadením (ochrana počítačů nestačí) Odděluje uživatele (prvek nespolehlivosti) od prvků ochrany

Vzdálená správa v cloudu až pro 250 počítačů

Střední odborná škola a Střední odborné učiliště, Hořovice

OPS Paralelní systémy, seznam pojmů, klasifikace

GTL GENERATOR NÁSTROJ PRO GENEROVÁNÍ OBJEKTŮ OBJEKTY PRO INFORMATICA POWERCENTER. váš partner na cestě od dat k informacím

STŘEDOŠKOLSKÁ ODBORNÁ ČINNOST. Obor SOČ: 18. Informatika. Školní sdílení PC obrazovek. School sharing PC screens

WORKWATCH ON-LINE EVIDENCE PRÁCE A ZAKÁZEK

APS mini.ed programová nadstavba pro základní vyhodnocení docházky. Příručka uživatele verze

Implementace systémů HIPS: ve znamení 64bitových platforem. Martin Dráb

Tato zpráva informuje o implementaci LMS (Learning Management Systém) Moodle konkrétně Moodle

TÉMATICKÝ OKRUH Softwarové inženýrství

Ing. Přemysl Brada, MSc., Ph.D. Ing. Martin Dostal. Katedra informatiky a výpočetní techniky, FAV, ZČU v Plzni

Knot DNS Resolver. Modulární rekurzivní resolver. Karel Slaný

FORTANNS. 22. února 2010

Šifrování Autentizace Bezpečnostní slabiny. Bezpečnost. Lenka Kosková Třísková, NTI TUL. 22. března 2013

Střední odborná škola a Střední odborné učiliště, Hořovice

Pokročilé architektury počítačů

Load Balancer. RNDr. Václav Petříček. Lukáš Hlůže Václav Nidrle Přemysl Volf Stanislav Živný

Programovací jazyky. imperativní (procedurální) neimperativní (neprocedurální) assembler (jazyk symbolických instrukcí)

Hypertext Transfer Protocol (HTTP/1.1 RFC 2616) Počítačové sítě Pavel Šinták

Analýza síťového provozu. Ing. Dominik Breitenbacher Mgr. Radim Janča

Jednotlivé hovory lze ukládat nekomprimované ve formátu wav. Dále pak lze ukládat hovory ve formátu mp3 s libovolným bitrate a také jako text.

Závěrečná zpráva projektu 475/2013 Fondu rozvoje CESNET

SSL Secure Sockets Layer

Registrační číslo projektu: CZ.1.07/1.5.00/ Elektronická podpora zkvalitnění výuky CZ.1.07 Vzděláním pro konkurenceschopnost

Nastavení programu pro práci v síti

Experimentální systém pro WEB IR

Specifikace požadavků. POHODA Web Interface. Verze 1.0. Datum: Autor: Ondřej Šrámek

v. 2425a Jak si na PC vypěstovat HTTP (WWW, Web) server a jak ho používat (snadno a rychle) by: Ing. Jan Steringa

ZÁLOHA A OBNOVA ABRA GEN

Management procesu I Mgr. Josef Horálek

Systém adresace paměti

09. Memory management. ZOS 2006, L.Pešička

Kerio IMAP Migration Tool

File Transfer Protocol (FTP)

WNC::WebNucleatCreator

BI-VWS. Vybrané partie z administrace Webového Serveru Autetizace, autorizace a kontrola přístupu Apache httpd

Základní informace: vysoce komfortnímu prostředí je možné se systémem CP Recorder efektivně pracovat prakticky okamžitě po krátké zaškolení.

VÝUKOVÝ MATERIÁL. Bratislavská 2166, Varnsdorf, IČO: tel Číslo projektu

konec šedesátých let vyvinut ze systému Multics původní účel systém pro zpracování textů autoři: Ken Thompson a Denis Ritchie systém pojmnoval Brian

Připravil: Ing. Jiří Lýsek, Ph.D. Verze: Webové aplikace

Tento studijní blok má za cíl pokračovat v základních prvcích jazyka Java. Konkrétně bude věnována pozornost rozhraním a výjimkám.

Střední odborná škola a Střední odborné učiliště, Hořovice

APS Web Panel. Rozšiřující webový modul pro APS Administrator. Webové rozhraní pro vybrané funkce programového balíku APS Administrator

Příručka nastavení funkcí snímání

Programovací jazyky. imperativní (procedurální) neimperativní (neprocedurální) assembler (jazyk symbolických instrukcí)

Instalace systému Docházka 3000 na operační systém ReactOS Zdarma dostupné kompatibilní alternativě k systému Windows

Úvod do Web Services

Spuštění instalace. nastavení boot z cd v BIOSu vložení CD s instal. médiem spuštění PC. nastavení parametrů instalace (F2 čěština)

Server-side technologie pro webové aplikace

WWW technologie. HTTP protokol

BI-AWD. Administrace Webového a Databázového serveru Virtualizace HTTP serveru

Instalační manuál. HelpDesk

Bezpečnost webových stránek

Vstupní požadavky, doporučení a metodické pokyny

Transkript:

Univerzita Karlova v Praze Matematicko-fyzikální fakulta BAKALÁŘSKÁ PRÁCE Jakub Břečka HTTP server se separací práv Katedra aplikované matematiky Vedoucí bakalářské práce: Studijní program: Studijní obor: Mgr. Martin Mareš, Ph.D. Informatika Programování Praha 2012

Tímto bych chtěl poděkovat Martinu Marešovi za vedení mé práce a za jeho odborné rady a poznámky.

Prohlašuji, že jsem tuto bakalářskou práci vypracoval samostatně a výhradně s použitím citovaných pramenů, literatury a dalších odborných zdrojů. Beru na vědomí, že se na moji práci vztahují práva a povinnosti vyplývající ze zákona č. 121/2000 Sb., autorského zákona v platném znění, zejména skutečnost, že Univerzita Karlova v Praze má právo na uzavření licenční smlouvy o užití této práce jako školního díla podle 60 odst. 1 autorského zákona. V Praze dne 21. 5. 2012 Jakub Břečka

Název práce: HTTP server se separací práv Autor: Jakub Břečka Katedra: Katedra aplikované matematiky Vedoucí bakalářské práce: Mgr. Martin Mareš, Ph.D. Abstrakt: Webservery hostující mnoho webů na jednom stroji často řeší problém se separací uživatelských práv. Standardní implementace totiž mají vyhrazeného uživatele, pod kterým jsou vyřizovány všechny požadavky. Existuje mnoho řešení, která se snaží spouštět uživatelské skripty nebo provádět požadavky v kontextu konkrétního uživatele. Většina z nich však nevyhovuje výkonem nebo neposkytuje úplnou separaci. Zaměřili jsme se na jeden z nejpoužívanějších webserverů, Apache HTTP Server, s cílem implementovat řešení, které by umožnilo mít nastavena unixová práva na adresářích tak, aby byly weby separované již na úrovni souborového systému. Klíčová slova: HTTP, server, Apache, bezpečnost, separace práv Title: HTTP Server with Privilege Separation Author: Jakub Břečka Department: Department of Applied Mathematics Supervisor: Mgr. Martin Mareš, Ph.D. Abstract: Webservers hosting multiple websites on a single machine have to solve a problem of privilege separation between users. Most implementations have a single system user, which is dedicated to serving all requests. There are many solutions trying to run user scripts or requests in the context of the appropriate user. However, most of them are not suitable because of low performance, or the level of user separation is not sufficient. We focused on Apache HTTP Server, one of the most widespread webservers, with the goal of implementing a solution that would allow the administrator to separate users at the level of the file system. Keywords: HTTP, server, Apache, security, privilege separation

Obsah 1 Úvod 3 1.1 Cíl práce................................ 4 1.2 Členění práce............................. 4 1.3 Používané pojmy........................... 5 2 Přehled dostupných řešení 7 2.1 suexec................................ 7 2.2 Řešení pro PHP............................ 8 2.2.1 safe_mode + open_basedir................. 8 2.2.2 suphp............................. 9 2.2.3 PHP-FPM........................... 9 2.3 Apache 2 ITK MPM......................... 10 2.4 Další řešení.............................. 11 3 Požadavky na řešení 13 3.1 Práva adresářů a souborů...................... 14 3.2 Persistentní HTTP spojení...................... 14 3.3 Uživatelská práva procesů...................... 16 3.4 Výkon a efektivita.......................... 17 4 Apache HTTP server 19 4.1 Historie Apache............................ 19 4.2 Základní operace webserveru..................... 20 4.3 Modularita Apache.......................... 21 4.4 MPM (Multi-processing modules).................. 21 4.4.1 MPM prefork......................... 22 4.4.2 MPM worker......................... 22 4.4.3 MPM event.......................... 23 4.5 Průběh zpracování požadavku.................... 23 4.6 APR (Apache Portable Runtime).................. 25 4.6.1 APR pools........................... 25 4.6.2 Filtry, buckets a brigades................... 26 4.6.3 APR hooks.......................... 27 4.7 Scoreboard............................... 28 4.8 Konfigurace serveru.......................... 29 4.8.1 Direktivy <Location>, <Directory>, <Files>....... 29 4.8.2 Virtuální hostitelé (virtual hosts).............. 30 1

5 Modul suidfork 31 5.1 Princip funkce............................. 31 5.2 Architektura modulu......................... 32 5.3 Konfigurace modulu......................... 33 5.3.1 Bezpečnostní kontexty.................... 33 5.3.2 Rozdělení modulů Apache do dvou tříd........... 35 5.3.3 Další konfigurace....................... 36 5.4 Implementace modulu........................ 36 5.4.1 Komunikace mezi procesy.................. 36 5.4.2 Serializace a předávání požadavku.............. 37 5.4.3 Notifikační mechanismus................... 38 5.4.4 Scoreboard.......................... 38 5.4.5 Systémové požadavky..................... 40 5.5 Struktura zdrojových souborů.................... 40 5.5.1 Struktura modulu suidfork.................. 40 5.5.2 Dokumentace......................... 42 6 Srovnání výkonu 43 6.1 Metodika............................... 43 6.2 Měření modulu suidfork....................... 44 6.2.1 Konfigurace testovacího stroje................ 45 6.2.2 Přenos statických souborů.................. 45 6.2.3 Zpracování PHP skriptů................... 45 6.3 Vyhodnocení.............................. 51 7 Závěr 53 7.1 Budoucí rozšíření........................... 53 Seznam použitých zkratek 55 Literatura 57 A Obsah přiloženého CD 61 2

Kapitola 1 Úvod Apache HTTP server je nejrozšířenějším webserverovým softwarem, běžícím na více než 300 milionech domén s více než 100 miliony aktivních webových stránek a na více než polovině z milionu nejvytíženějších webů [1]. Častým využitím Apache je u poskytovatelů webhostingu, velmi typickou kombinací služeb nabízených na hostingu je Linux, Apache, PHP a MySQL. Jedno z důležitých kritérií bezpečnosti serveru a služeb je oddělení jednotlivých uživatelských účtů. Na typickém unixovém stroji je webovému serveru vyhrazen uživatelský účet, pod kterým běží. Aby mohl webserver poskytovat soubory jednotlivých uživatelů, musí k nim mít přístup, tedy je nutné, aby data uživatelů byla přístupná uživateli, pod kterým běží Apache. Z tohoho vyplývá, že jakýkoliv skript (CGI, PHP,... ), který bude spuštěn Apachem, a poběží tedy s jeho právy, bude mít přístup k datům všech uživatelů. Často se tento problém řeší přímo v aplikaci, ve které se skripty spouštějí. Například PHP umožňuje v konfiguraci nastavit direktivy open_basedir a safe_mode (safe mode je ovšem již z poslední verze PHP odstraněn), které zabraňují skriptům v přístupu mimo vymezené adresáře. Fakt, že je toto opatření implementováno v aplikaci a není řešeno na úrovni operačního systému, vytváří prostor pro zranitelnosti a programátorské chyby. Pokud se útočníkovi povede najít chybu v PHP, získá opět přístup k cizím datům. Historie ukazuje, že v jádře PHP bylo nalezeno mnoho zranitelností, navíc je zveřejněn druh chyb, známý jako Interruption Vulnerabilities, jehož mnoho variant zveřejnil Stefan Esser v roce 2007 [2] a další v roce 2010 [3]. Řada těchto problémů byla odstraněna, nicméně princip těchto zranitelností je zakořeněn hluboko v jádře PHP a není možné mu zabránit. Důsledkem toho je, že vývojáři oznámili, že některé chyby vůbec nebudou odstraněny, a v současnosti existují i několik let staré funkční exploity, které umožňují v kontextu webového serveru spustit libovolný kód nebo číst a měnit libovolnou paměť. Vzhledem k tomu, že je PHP natolik populární jazyk pro běh webů, a navíc se jedná o jednu z nejběžněji poskytovaných hostingových služeb, je zapotřebí zajistit izolaci uživatelů na serveru jiným způsobem, nejlépe takovým, který nelze principiálně prolomit chybou v aplikaci. Sami autoři PHP silně doporučují řešit ochranu uživatelů na úrovni operačního systému (a nastavených práv souborů a adresářů), neboť jen tak je možné zajistit, že k cizímu souboru nebude možné přistoupit. 3

Aby však bylo možné uživatelským adresářům nastavit práva, která neumožní čtení jinými uživateli, je nutné změnit způsob, jakým fungují běžné webové servery. 1.1 Cíl práce Tato práce má za cíl implementovat do Apache HTTP serveru modul, který umožní jednotlivé HTTP požadavky vyřizovat s právy konkrétního uživatele, který vlastní dané soubory a skripty. Pokud se toto chování správně implementuje, bude výsledkem izolace uživatelů, která bude zajištěna v jádře operačního systému. Tato úroveň je ovšem považována za maximálně bezpečnou, neboť je to zásadní funkce kernelu, která je na běžných operačních systémem prověřena desítkami let používání. Neméně důležitou součástí této práce je zajistit, aby výsledný modul nepředstavoval příliš velkou zátěž, jednak co se týče výkonu a efektivity daného řešení, a také, aby konfigurace a bezpečnostní nastavení nebylo příliš komplikované. Celá práce se zaměřuje pouze na unixové operační systémy, protože drtivá většina webových serverů je provozována právě na těchto systémech. Typickým představitelem je Linux, který bývá na hostingových serverech nainstalován nejčastěji. Druhotným cílem je popsat architekturu webserveru Apache tak, jak v aktuální verzi funguje, protože sice existuje řada publikací pro vývojáře modulů, nicméně většina vydaných knih obsahuje zastaralé informace a popisuje často pouze chování Apache verze 1.3. Vydání větve 2.0 mění podstatnou část fungování webserveru, a další výrazné změny přišly s verzemi 2.2 a 2.4, o nichž v tuto chvíli neexistuje prakticky žádná literatura. 1.2 Členění práce Text je rozdělen do následujících částí: Kapitola 2 popisuje, jaká řešení jsou v současné době k dispozici, a diskutuje o jednotlivých produktech, jejich možnostech, použitelnosti, bezpečnosti a případných dalších výhodách a nevýhodách. V kapitole 3 rozebereme na základě již existujících produktů, jaké požadavky klademe na ideální řešení, a co tyto požadavky přinášejí za problémy. Kapitola 4 poskytuje přehled, co vlastně je součástí webserveru Apache, jaké úlohy provádí, jakým způsobem funguje uvnitř a jaké prostředky mají vývojáři modulů a rozšíření k dispozici. O samotném vlastním modulu do Apache, který implementuje požadované vlastnosti, mluví kapitola 5. Popisuje architekturu modulu, proč byla takto zvolena a jaké z toho plynou důsledky. V kapitole 6 srovnáváme výkon při použití našeho modulu s jinými konkurenčními řešeními za různých podmínek. Kapitola 7 tuto práci uzavírá a má za cíl posoudit, nakolik se podařilo stanovené požadavky realizovat. 4

1.3 Používané pojmy Celý a správný název webového serveru, kterého se týká tato práce, je Apache HTTP Server, často se mu hlavně z historických důvodů říká httpd (zkratka za HTTP daemon), ale ještě častěji je server nazýván pouze Apache. Pod značkou Apache je však vydávána celá řada dalších produktů (např. sestavovací nástroj Apache Ant, databázový server CouchDB, Javový server Apache Tomcat nebo revizní systém SVN), také je tímto názvem označena zaštiťující organizace Apache Software Foundation [4] a licenční smlouva Apache License pro svobodný software. Většina zmiňovaných produktů je vydána právě pod touto licencí. Přesto je Apache HTTP Server chápán jako klíčový produkt této společnosti a jejích vývojářů a pokud se tedy v této práci mluví o Apachi, myslí se tím webserverový software. HTTP (Hypertext Transfer Protocol) je aplikační protokol používaný pro komunikaci v síti WWW a pro přenos internetových stránek a jeho aktuální verze 1.1 je specifikována ve standardu RFC 2616 [35] z roku 1999. Jedná se o bezstavový protokol pracující nad transportní vrstvou TCP. Je založený na principu požadavku a odpovědi. Po jednom aktivním TCP spojení může klient zaslat více požadavků a z této vlastnosti vyplývá řada důsledků, které jsou v této práci dále popsány. Jedním z dostupných prostředků pro programování dynamických webů je CGI (Common Gateway Interface), což je standard určující rozhraní mezi webovým serverem a skriptem nebo externí aplikací, která má za úkol vyřídit daný HTTP požadavek. Ještě více populární je používání jazyků přímo určených pro vývoj webů, např. PHP [38], který je dnes jedním z nejpoužívanějších skriptovacích jazyků. Pro zabezpečení komunikace mezi webserverem a klientským strojem slouží technologie SSL (Secure Sockets Layer) a TLS (Transport Layer Security), které zajišťují šifrovací vrstvu. Implementace pro webové servery se jmenuje HTTPS a jedná se o způsob, jak zajistit přenos HTTP před odposloucháváním a při použití správných certifikátů a důvěryhodných autorit (tzv. chain of trust) i proti útokům typu man in the middle. Tato práce se zaobírá unixovými uživatelskými právy. Na běžném unixovém systému, jakým je třeba Linux, má každý soubor na disku svého vlastníka, který je určen číslem daného uživatele (user identifier, UID). Tato čísla jsou většinou definována v souboru /etc/passwd, kde jsou také určena jména uživatelů. Obdobně má každý soubor určenu i skupinu, do které patří (group identifier, GID). Souborová práva určují, zda je daný soubor pro čtení, zápis a spouštění, a také udávají, komu jsou tato práva dostupná: vlastníkovi, skupině nebo všem uživatelům systému. Speciální uživatel jménem root (s UID 0) má vždy přístup ke všem souborům a procesům. Existuje řada operací, tzv. privilegované, které smí provádět pouze tento uživatel. Např. je to otevření TCP portu pro naslouchání s číslem menším než 1024. Koncept virtuálních hostitelů (virtualhostů) je způsob, jak provozovat více webů na jednom stroji. Správně nakonfigurovaný webserver pozná podle příchozího požadavku (zejména podle hlavičky Host), jakého webu se tento požadavek týká. 5

Unixový mechanismus zvaný chroot (change root) umožňuje spustit proces tak, že se jako kořenový adresář jeví jiný, administrátorem zvolený adresář. Tato operace se provádí systémovým voláním chroot a smí ji provést pouze uživatel root. Typicky se po tomto volání provede změna UID, aby se proces již z chrootu nemohl vrátit zpět. 6

Kapitola 2 Přehled dostupných řešení Tato kapitola přináší (jistě však ne úplný) seznam již existujících modulů či jiných způsobů, které se snaží vyřešit výše zmíněný problém, tj. izolaci jednotlivých uživatelů a jejich dat v rámci webserveru před cizím přístupem. Existuje řada řešení, které umožňují různými způsoby a s různou efektivitou spouštět uživatelské skripty. Jednou z nejjednodušších metod spuštění uživatelského skriptu pro vyřízení HTTP požadavku je přes CGI. Jeho problémem je poměrně velká časová náročnost, protože vyrobení procesu (přes systémové volání fork), spuštění interpretu a vykonání skriptu přináší značný overhead. Proto vzniklo mnoho možností, jak zamezit nutnosti vyrábět nový proces každému požadavku. Protokol FastCGI [21] je přímo navržen pro zrychlení spouštění CGI skriptů. Webserver při použití tohoto protokolu předává příslušné požadavky jinému procesu, tzv. FastCGI serveru. Ten využívá výkonné procesy, které běží dlouhodobě a zpracovávají více požadavků, místo toho, aby se spouštěl nový proces pro každý požadavek. V Apachi je implementována příslušná webserverová část protokolu v modulu mod_fastcgi. Často ještě efektivnějším způsobem je zavedení interpretu skriptů přímo do procesu Apache, čímž probíhá zpracování úplně bez vytváření procesu. Příkladem jsou moduly mod_perl a mod_php, což jsou preferované způsoby pro běh perlových a PHP skriptů. Moduly, které však běží přímo ve výkonném procesu Apache, získávají tímto způsobem všechna oprávnění, která má webserver, takže pokud tento provozuje více webů, má interpret přístup ke všem. Zde se tedy zaměřujeme pouze na implementace, které nějakým způsobem umožňují zamezit neoprávněnému přístupu. 2.1 suexec Modul (nebo spíše funkce) suexec umožňuje administrátorovi nastavit, aby se určité skripty nespouštěly s právy webserveru, ale s právy konkrétního uživatele. Technicky je tento způsob realizován pomocí dvou částí: modulu do Apache a samostatného spustitelného souboru, který má nastaven tzv. setuid bit. Pokud je tento speciální unixový příznak nastaven, spustí se daný program vždy s právy jeho vlastníka, nezávisle na tom, jaký uživatel jej doopravdy spouští. V případě suexecu je vlastníkem speciálního programu uživatel root, který jediný smí používat systémové volání setuid. Tímto voláním se program přepne 7

do kontextu jiného uživatele, jehož ID je parametrem volání. U suexecu je to uživatel, který je nastaven konfigurační direktivou SuexecUserGroup. Po přepnutí do správného kontextu se pak spustí příslušný skript daného uživatele. Tato funkce je integrovaná do Apache již od verze 1.2. Jedná se o jedno z prvních řešení separace uživatelských práv, a díky přísnému bezpečnostnímu modelu je i dostatečně bezpečné, pokud je ovšem vše správně nastaveno. Zásadním nedostatkem a hlavním důvodem, proč se dnes preferují jiná řešení, je příliš velká doba obsluhy a nízký výkon. Pro zpracování každého požadavku je nutné vytvořit nový proces, provést řadu ověřování, přepnout UID a poté spustit (v rámci jednoho procesu, pomocí systémového volání execve) daný skript. Navíc celé toto chování funguje pouze pro CGI skripty, a nelze takto zpracovávat požadavky na statické soubory nebo na obsah generovaný moduly v Apachi. Další komplikací pro využití suexec je netriviální konfigurace, která navíc pro správné zajištění bezpečnosti vyžaduje detailní znalost fungování tohoto modulu. 2.2 Řešení pro PHP 2.2.1 safe_mode + open_basedir Vývojáři jazyka PHP a jeho prostředí se snaží zajistit, aby spouštěným PHP skriptům bylo možné omezit jejich interakci se systémem a aby neměly stejné možnosti jako uživatelský účet, pod kterým interpret běží. Z toho důvodu jsou v PHP přítomny konfigurační direktivy safe_mode a open_basedir. Zapnutý safe mode způsobuje mimo jiné to, že není možné spouštět externí příkazy a všechny funkce pracující se soubory kontrolují, zda se vlastník daného souboru shoduje s vlastníkem právě běžícího skriptu. Vzhledem k tomu, že PHP je plně interpretovaný jazyk (ač za běhu kompilovaný do bajtkódu), a je tedy pod kontrolou interpretu, mohlo by důsledné ověřování zajistit dostatečnou izolaci a kontrolu spouštěného skriptu. Bohužel však tato funkce spoléhá na správné použití ve všech vestavěných (i cizích) funkcích a modulech; to se však vývojářům PHP nedaří zajistit. Zranitelnosti využívající nesprávnou implementaci (nebo i pouhé opomenutí) této funkcionality. Sami autoři pod několikaletým nátlakem veřejnosti [8] přestali safe mode podporovat, protože je principiálně nefunkční, a z řady 5.4 je tato možnost již odstraněna. Direktiva open_basedir omezuje skriptům přístup pouze na určené adresáře. Ačkoliv je princip chyb, které umožňovaly toto nastavení obejít, úplně stejný jako v případě safe mode, je tato možnost plně podporovaná. Velká část webhostingů využívá právě tuto konfigurační direktivu jako prakticky jediný způsob izolace uživatelských PHP skriptů. Jádro jazyka PHP však není schopné dostatečně kontrolovat to, co může spouštěný skript provádět. Stefan Esser zveřejnil řadu zranitelností jádra PHP, připomeňme např. chyby s označením MOPS-2010-001 [9] a MOPS-2010-053 [10]. První jmenovaná umožňuje přepsat interní strukturu, která obsahuje ukazatele na funkce (obdoba tabulky virtuálních metod). Tím umožní útočníkovi provést instrukci CALL na libovolnou adresu, což může vést ke spuštění libovolného kódu v kontextu procesu, který zpracovává daný PHP skript. Druhá zranitelnost, která je typu Interruption Information Leak, umožňuje z PHP skriptu přečíst paměť in- 8

terních struktur PHP a také přečíst paměť na libovolné adrese. Kombinaci těchto dvou zranitelností je možné zneužít k získání práv interpretu PHP. Co je ovšem na těchto zranitelnostech zajímavé oproti ostatním zveřejněným chybám v PHP, je fakt, že vývojáři tyto chyby neodstranili, protože by to vyžadovalo příliš velké změny v jádře PHP, který by způsobily zpětnou nekompatibilitu. Takže i poslední verze PHP 5.4.0, která vyšla v březnu 2012, oběma těmito zranitelnostmi trpí. Je tedy vidět, že jakákoliv zabezpečovací a omezovací řešení, která jsou v současnosti implementována v rámci jádra PHP, poskytují pouze iluzi bezpečnosti a je zapotřebí uplatňovat bezpečnostní politiku na jiné úrovni, nejlépe na úrovni operačního systému. Navzdory tomu, že ochrana aplikace v případě PHP je neúčinná, je stále možné mít efektivní bezpečnostní mechanismy v uživatelském prostoru (user mode), příkladem takto funkčních prostředí mohou být např. platformy Java a.net a jejich virtuální stroje a běhová prostředí [11]. Princip překladu a spouštění Javy,.NETu a PHP kódu je prakticky stejný, všechny tyto jazyky nejprve kompilují zdrojový kód do bajtkódu, jehož jednotlivé instrukce jsou za běhu prováděny virtuálním strojem (VM). Jinou nevýhodou zapnutého safe módu a nastaveného open_basedir je jednak drobná režie při každém přístupu k souborovému systému (je nutné ověřovat cesty a přístupová práva), ale také jsou vypnuté souborové keše. S vypnutým safe módem se kešují volání funkce realpath, což značně zrychluje funkce include a podobné, které načítají další skripty. Takže vypnutí safe módu může mít i pozitivní vliv na výkon. 2.2.2 suphp Jedno z funkčních řešení problémů s bezpečností PHP je modul do Apache zvaný suphp, který využívá ke spouštění PHP skriptů speciální program s nastaveným setuid bitem (pod uživatelem root) [12]. Přes tento skript se spouští všechny PHP skripty a po ověření, že se daný skript (předaný jako parametr na příkazové řádce) opravdu smí spustit, se pomocí systémového volání setuid přepne ze superuživatelského režimu do uživatele, který je vlastník daného skriptu. Poté se spustí interpret PHP (samostatně, ne jako modul) pomocí execve. Hlavním problémem tohoto řešení je výkon, protože je kvůli forkování prakticky stejně pomalé jako suexec. Navíc je modul suphp možné provozovat pouze pod Apachem řady 1.3, 2.0 a 2.2. S novou řadou 2.4 zatím projekt není možné zkompilovat. Navíc je otázka, zda vůbec bude podpora pro nové verze Apache zajištěna, protože poslední aktualizace projektu je z března roku 2009. 2.2.3 PHP-FPM Další z možností, jak zajistit bezpečné prostředí pro PHP skripty, je PHP-FPM (FastCGI Process Manager). Pomocí protokolu FastCGI probíhá komunikace mezi webserverem a FastCGI serverem, kterému je zaslán každý CGI požadavek. Tento démon si poté sám řídí zpracování jednotlivých požadavků, typicky má k dispozici řadu výkonných podprocesů, které po zpracování požadavku zůstávají běžet a čekají na další požadavek. 9

Tím je separován samotný webserver od interpretu skriptů, který běží v jiném procesu a často i pod jiným uživatelem. Pád skriptu nebo jeho interpretu tedy nepřeruší provoz webserveru. Řídící proces PHP-FPM běží pod uživatelem root a stará se o vyrábění podprocesů a rozdělování požadavků. Různé podprocesy mohou běžet pod různými UID a mohou mít různá další bezpečnostní nastavení. Tyto výkonné procesy vznikají a jsou ukončovány podle potřeby. Z hlediska výkonu je toto řešení výrazně lepší než suexec, protože nevyžaduje vyrábění procesu pro každý požadavek nebo spojení. Pochopitelně je nutné uživatelské procesy vytvořit, ale to se děje jen jednou a poté jsou procesy recyklovány. Nedostatkem je to, že tato implementace řeší pouze bezpečnost PHP skriptů, ale složka, ve které je skript umístěn, musí být stále přístupná pro protokolové procesy webserveru. Nicméně je přesto tento přístup poměrně populární, protože daleko více průniků pochází právě přes chyby a zranitelnosti v PHP, než ty v jiných modulech webového serveru. 2.3 Apache 2 ITK MPM ITK [13] je alternativní modul do Apache, který nahrazuje standardní vytváření výkonných procesů (nebo vláken) vlastním mechanismem. Ten umožňuje nastavit různé UID a GID pro jednotlivé virtuální hostitele. Samotný webserver běží pod uživatelem root až do okamžiku, kdy je načten požadavek a je možné určit, pod kterým uživatelem má být požadavek vyřízen. To pochopitelně značně zvětšuje prostor pro bezpečnostní chyby a jejich dopad, protože samotné načtení hlaviček požadavku může být velmi komplikovaná záležitost, např. kvůli SSL/HTTPS. Kód obsluhující SSL spojení je rozsáhlý a navíc se opírá o knihovnu OpenSSL. Toto řešení může paradoxně znamenat zhoršení zabezpečení, právě kvůli tomu, že přidává velké množství kódu běžícího pod superuživatelem a případná zranitelnost v něm pravděpodobně způsobí kompromitaci celého systému. Co se týče výkonu, je na tom ITK podobně jako suexec, protože přidává jeden fork na každý požadavek. Výhodou tohoto řešení je, že je možné mít práva adresářů jednotlivých webů (virtualních hostitelů) nastavena na 700, takže nebude možné z jednoho webu přistupovat k datům jiného. Na druhou stranu, kvůli tomu, že je separace řešena na úrovni spojení, může se stát, že v rámci jednoho spojení přijdou požadavky na různé weby, pro které jsou zapotřebí jiná práva. V tomto případě ITK násilně přeruší dané TCP spojení a počítá s tím, že klient se připojí znovu a bude požadavek opakovat s novým spojením. Nutno dodat, že tento způsob je povolen, co se týče standardu HTTP, protože u persistentních spojení se může server kdykoliv rozhodnout ukončit příliš dlouho trvající spojení. Nicméně opětovné navázání TCP spojení s sebou nese určitou režii a navíc tímto není možné mít různé uživatele v rámci jedné domény (jednoho virtuálního hostitele). 10

2.4 Další řešení Pro webserver Apache bylo implementováno několik modulů, které se pokoušely řešit podobný problém jako tato práce, ale které již nejsou vyvíjeny nebo nejsou dostupné pro aktuální verzi Apache (v současnosti je aktivně vyvíjena řada 2.4). Za zmínku stojí modul Metux [14] (poslední vydání je z roku 2004), který umožňoval spouštět jednotlivé virtuální hostitele pod různými uživateli. Každému uživateli je při startu serveru spuštěn minimálně jeden proces, který vyřizuje požadavky na příslušné virtualhosty, a v rámci tohoto procesu běží vlákna, která obsluhují jednotlivá spojení. Podobným projektem byl modul perchild [15], což je předchůdce Metuxu, který byl dokonce přítomen v hlavní větvi Apache řady 2.0 jako experimentální modul. Peruser je další implementace založená na Metuxu, která mění vícevláknový přístup na jednovláknový, čímž je možné provozovat i moduly, které nejsou pro vlákna uzpůsobena. Bohužel poslední aktualizace tohoto projektu je z roku 2007. Existuje celá řada dalších více či méně úspěšných pokusů o vyřešení nastíněného problému, většina z nich je však implementována jedním z již popsaných způsobů: mod_suid2 [16] principiálně stejný jako ITK mod_ruid postavený na mod_suid2, ale využivá Linux capabilities k přepínání UID a recykluje tak procesy, takže se nemusí pro každé spojení vyrábět nový. Nicméně otevírá bezpečnostní díru v tom, že případná zranitelnost umožní útočníkovi získat práva superuživatele. mod_sucgid [17] obdobné řešení jako suexec 11

12

Kapitola 3 Požadavky na řešení Tato práce si klade za cíl navrhnout a implementovat rozšíření (modul) do webového serveru Apache, se kterým bude možné následující: zpřístupnit uživatelský adresář na webovém serveru, který bude mít nastavena unixová práva 700 (přístup má pouze vlastník adresáře) umožnit v takovémto adresáři zpracovávat nejen skripty, ale i číst další datové soubory zachovat funkci souborů.htaccess a.htpasswd v těchto adresářích (nastavuje se jimi konfigurace specifická pro daný adresář) zpřístupnit uživatelské adresáře ve tvaru /~user/index.html s právy daného uživatele zajistit, aby řešení bylo dostatečně efektivní a použitelné v reálných situacích zařídit, aby výkonná část neběžela jako uživatel root znovuvyužít jednotlivé procesy nesmí se vytvářet proces při každém požadavku ukončit zpracovávání příliš dlouho běžícího požadavku zachovat veškeré funkce (nebo co největší množství) jádra Apache a jeho modulů, zejména podporu SSL/HTTPS, autentifikaci a další bezpečnostní prvky. Je zřejmé, že jakékoliv řešení splňující tyto body bude mít nižší výkon než standardní instalace Apache, protože bude vyžadovat netriviální ověřování a manipulaci s požadavky. Nicméně je zapotřebí si uvědomit, že při dnešním využití dynamicky generovaných webových stránek je náročnost samotného výkonného skriptu (typicky PHP, Perl nebo CGI) řádově vyšší než zpracování na straně webserveru. Prakticky každý web využívá nějaké databázové úložiště a získávání a ukládání dat je často největší zátěží (jak délkou zpracování tak i procesorovým časem). Případná zvýšená režie nemusí tedy degradovat výkon Apache jako webového serveru. 13

3.1 Práva adresářů a souborů Častým problémem při vytváření a zprovozňování webového systému je otázka, kam uložit přístupové údaje k databázi. Uživatelské jméno a heslo jsou většinou jediným autentifikačním mechanismem, a jedná se tedy o velmi citlivé údaje. Pokud provozujeme webovou aplikaci na hostingu, nemáme většinou jinou možnost, než tyto údaje uložit do nějakého souboru, v případě PHP aplikací se většinou jedná o soubor s názvem config.php nebo podobně. Stejně se často řeší i autentifikace a ukládání přihlašovacích údajů uživatelů pro HTTP autentifikaci. V případě webserveru Apache se pro toto využívá soubor.htpasswd, ve kterém jsou uložené heše hesel. Jistě bychom našli i další případy, kdy je zapotřebí ukládat velmi citlivé údaje do souborů a adresářů, aby k nim webová aplikace a webserver měly přístup. Jistě bychom v těchto případech chtěli, aby dané citlivé soubory měly nastavena přístupová práva tak, aby si jejich obsah přečetl pouze jejich vlastník (na unixových systémech jsou to práva 700). To se však v běžných prostředích webserverů jeví jako nemožné, protože je nutné, aby k takovýmto údajům měl přístup i webserver, který běží v kontextu jiného uživatele. Často je takto vytvořen samostatný uživatelský účet pouze pro tyto účely. V kontextu webového serveru ale typicky běží i samotná webová aplikace při zpracování požadavku. Vzhledem k tomu, že je zapotřebí, aby všechny soubory, které tvoří obsah webu nebo jsou nutné pro jeho provoz, byly přístupné z tohoto kontextu, má každá webová aplikace vždy přístup k webovým datům všech ostatních uživatelů (na úrovni operačního systému a souborových práv). A to přesto, že fakticky je tato aplikace vlastněná běžným uživatelským účtem, který tato práva mít nemusí. Je logické, že bychom chtěli, aby uživatelé měli svá data zpřístupněná na webu, a zároveň, aby tato data byla v adresářích s právy 700 (přístup má pouze vlastník). Způsob, jak toho dosáhnout, spočívá v tom, že pokud server obdrží HTTP požadavek na soubor do daného adresáře, přepne se do jiného uživatelského účtu a s nově získanými právy vyřídí tento požadavek. Na unixových systémech je toto realizováno voláním setuid, které smí provést pouze superuživatel a ze kterého se již nelze přepnout zpět. Pokud tedy bude požadavek vyřizován s právy daného uživatele a webová aplikace poběží v tomto procesu, nebude mít přístup k datům ostatních uživatelů. 3.2 Persistentní HTTP spojení Protokol HTTP ve verzích 0.9 a 1.0 specifikoval, že po vyřízení požadavku je dané spojení mezi serverem a klientem uzavřeno. To znamenalo, že existovala jednoznačná korespondence mezi spojením a požadavkem. Serverový proces, který zpracovával požadavek, může mít pod kontrolou celé spojení, protože klient neočekává od serveru po vyřízení požadavku nic dalšího. V aktuální verzi protokolu HTTP má však klient možnost navázat persistentní spojení, ve kterém může serveru zaslat více požadavků. Tato vlastnost je zcela pochopitelná, protože vytvoření TCP spojení s sebou nese značnou režii, jednak co se týče přenášených dat, ale také komunikující stanice musejí alokovat prostředky pro každé spojení. Zejména ale musejí obě strany při navazování spojení čekat na 14

odezvu, což je obzvlášť časově náročné, pokud je vysoká latence mezi webserverem a klientem (v reálných situacích jsou tyto strany často i na jiných kontinentech). Pokud klient chce vytvořit persistentní spojení, zašle v HTTP požadavku hlavičku Connection: Keep-Alive, a pokud tuto funkci server podporuje, zašle stejnou hlavičku i v odpovědi. Poté, co se vyřídí požadavek, je spojení zachováno a klient může zaslat další. Aby toto mohlo fungovat, musí server buďto oznámit dopředu délku dokumentu, který zasílá jako odpověď, ve formě hlavičky Content-length; klient totiž musí poznat, že již obdržel celou odpověď. Pokud délka dokumentu není dopředu známá, může server odeslat data v tzv. chunked kódování, kdy jsou odesílaná data rozdělena do bloků a před každým zaslaným blokem je uvedena i jeho délka. Toto kódování oznamuje server hlavičkou Transfer-Encoding: chunked. Server umožňující klientům držet otevřená spojení může snadno dojít k tomu, že vyčerpá svůj limit na počet současných spojení, která zvládne obsluhovat. Proto je zapotřebí aplikovat různá omezení, přinejmenším časový limit, do kterého musí klient odeslat další požadavek po vyřízení předchozího. Také je vhodné omezit maximální počet požadavků, který lze po jednom spojení odeslat. Při překročení těchto limitů může HTTP server spojení jednoduše ukončit nebo s posledním požadavkem ohlásit pomocí hlavičky Connection: close, že spojení bude po vyřízení uzavřeno. Představme si, že máme webserver, který umí vyřizovat požadavky s právy toho uživatele, kterému patří dokument, ke kterému přistupujeme. Může se stát, že v jednom persistentním spojení přijdou požadavky na dvě různá URL, která patří různým uživatelům; typicky by adresy mohly být: http://server/~user1/ http://server/~user2/ Proces, který zpracovává takovéto spojení a který by uměl vyřídit tyto dva požadavky, se nemůže přepnout do kontextu uživatele user1, protože by pak nebylo možné vyřídit druhý požadavek. Bylo by možné např. vyřídit první požadavek a poté spojení předat jinému procesu, nicméně v takovémto chování se skrývá bezpečnostní problém. Pokud proces opravdu bude vyřizovat první požadavek s právy daného uživatele, může tento uživatel změnit chování tohoto procesu a ukrást dané spojení. To pak může využít a klientovi zasílat falešné odpovědi na URL jiných uživatelů. Řešením tohoto problému je oddělit zpracování spojení a zpracování jednotlivých požadavků. Proces, který přijme spojení (a má k němu tedy plný přístup) z něj přečte požadavek, a uživatelskému procesu předá pouze tento jeden požadavek k vyřízení. Konkrétní uživatel, jehož proces provádí zpracování, stále může ukrást procesu požadavek a zaslat falešnou odpověď, nicméně toto chování již nelze považovat za problém, protože uživatel může ovlivnit pouze požadavky na svá data. Takže pokud by měl nějaký důvod to dělat, stačí mu změnit svá data a nemusí ovlivňovat běžící procesy. Pochopitelně je klíčové v takovémto návrhu zajistit, aby uživatelskému procesu bylo důvěřováno co nejméně. Tedy aby např. proces, který zpracovává spojení, nebylo možné ovlivnit uživatelským procesem jinak, než vrácením odpovědi na požadavek. Také je nutné při výrobě tohoto procesu zajistit, aby mu nebyla 15

předána žádná oprávnění a zdroje, které nemá mít. Typickým příkladem takovéhoto problému může být neuzavřený file descriptor při forkování procesu. 3.3 Uživatelská práva procesů Jednou ze základních metodik k zajištění bezpečnosti daného systému nebo služby je minimalizace pravomocí, anglicky least privilege principle [18]. Každý proces by měl běžet v takovém kontextu, aby měl práva pouze na to, co potřebuje ke svému správnému fungování. Na unixových systémech je řada operací, které smí provádět pouze superuživatel (root, uživatel s ID 0). Mimo jiné se jedná o změny systémové konfigurace, správu uživatelů nebo o možnost restartovat počítač. Na proces s právy uživatele root se nevztahují prakticky žádné kontroly přístupu a může tak se systémem dělat všechny operace. Tím pádem je zřejmé, že pod tímto uživatelem by mělo běžet co nejméně procesů a pokud nějaká služba tyto práva vyžaduje, tak aby množství kódu, které takto bude běžet, bylo co nejmenší. Pro potřeby webového serveru je podstatnou privilegovanou operací (tj. taková, že ji smí provádět pouze root) otevření TCP portu s číslem menším než 1024. Standardní port pro službu HTTP má číslo 80, a tedy každý webserver potřebuje být pro tuto operaci spuštěn jako root. Nicméně privilegovanou operací je pouze volání bind, které přiřadí socketu adresu a port, další práce s takto přiřazeným socketem (např. volání listen a accept) již superuživatelská oprávnění nevyžaduje. Takže je velmi typické, že webserver je sice spuštěn jako root, ale spustí se takto pouze velmi malá část inicializačního kódu (včetně volání bind) a následně si proces sám sníží oprávnění zavoláním setuid, čímž se přepne na jiného uživatele. Proto bývá v systému speciální uživatelský účet, často pojmenovaný nobody, apache nebo www-data, který slouží tomuto účelu a pod kterým poté běží výkonné procesy webserveru. Pokud chceme, aby server prováděl požadavky pod různými uživateli, musí se vyrábět nebo přepínat procesy s různými UID. K tomu jsou také zapotřebí práva uživatele root. Jak již bylo zmíněno, standardně není možné se po zavolání setuid přepnout zpátky nebo znovu zavolat toto systémové volání, protože po jeho provedení již proces běží jako neprivilegovaný uživatel a nemá pravomoc se přepnout na jiné UID. To je pochopitelné, protože jinak by se tím otevírala bezpečnostní díra. Částečně toto obchází koncept zvaný capabilities, který byl v návrhu normy POSIX (ale později z ní byl stažen [19]) a implementován je např. v Linuxu. Např. příznak CAP_NET_BIND_SERVICE umožňuje danému procesu naslouchat na portech s číslem menším než 1024, i pokud tento proces neběží pod rootem. Pokud má proces nastaven příznak CAP_SETUID, smí libovolně manipulovat se svým UID, pod kterým běží, a obdobně funguje i CAP_SETGID, která se týká GID. Toto využívá modul mod_ruid zmiňovaný v předchozí kapitole. Zásadním nedostatkem tohoto řešení je, že jakákoliv bezpečnostní chyba v procesu s touto způsobilostí bude znamenat kompromitaci celého systému. Proto je zapotřebí, aby ideální řešení, které zřejmě stále bude vyžadovat část kódu běžícího pod superuživatelem, mělo tuto část co nejmenší, a aby se nepoužíval mechanismus, který by případnou zranitelností ohrozil celý systém. Jinými slovy, aby co největší část kódu měla co nejmenší pravomoce. 16

3.4 Výkon a efektivita Triviální implementace webserveru by mohla vypadat takto: Jeden proces naslouchá na portu 80 (a nevyžaduje k tomu práva root), když přijde spojení, vytvoří nový proces (voláním fork), který se stane obsluhou tohoto spojení. Problémem tohoto přístupu je velká neefektivita. Fork je na většině systémů relativně drahá operace [20], a provádět ji při každém příchozím spojení je u vytíženějších serverů neúnosné. Stejným problémem trpí rozhraní CGI, kde je však neefektivita ještě větší. Fork a exec se provádějí při každém HTTP požadavku a je tedy přirozené, že vznikla řada řešení, které umožňují spouštět CGI skripty bez potřeby vytváření nových procesů (recyklace procesů). Nejznámějším protokolem, který toto přináší, je FastCGI [21], což je velmi populární alternativa ke spouštění PHP místo běhu v rámci procesu Apache přes mod_php. V Apachi od verze 2.0 existuje speciální druh modulů, kterým se říká MPM (Multi-processing modules). Tyto moduly určují základní chování, co se týče přijímání a zpracování spojení a vytváření potřebných výkonných jednotek. Těmito jednotkami mohou být vlákna nebo procesy, případně kombinace obojího, podle toho, jaké MPM je zvoleno. Typická instalace Apache a PHP využívá předvytvořené procesy (pomocí MPM prefork) nebo vlákna (worker a event), které jsou recyklovány, a není tedy třeba vytvářet nové procesy, pokud se zátěž serveru nezvedne. Ve výkonných procesech je pomocí mod_php zaveden celý interpret PHP, takže během celého zpracování není vůbec zapotřebí vytvářet nové procesy nebo spouštět jiné programy. Rychlost takového zpracování je dostatečně vysoká a úzkým hrdlem začíná být samotný interpret PHP. Větší aplikace v PHP se skládají z mnoha souborů, které je potřeba při každém požadavku otevřít, načíst, naparsovat a vygenerovat z nich bajtkód. Ačkoliv je jádro PHP při kompilaci velmi rychlé, pokud se tyto operace provádějí při každém požadavku, je tato režie nezanedbatelná. Proto jsou k dispozici nástroje, jakými jsou např. APC [33] nebo XCache [23], které kešují výsledek kompilace. Jejich funkce spočívá v tom, že si vyhradí určité množství sdílené paměti, do které se ukládá vygenerovaný bajtkód zkompilovaných skriptů. Při příchozím požadavku se nejprve ověří čas poslední změny daného souboru, a pokud je to možné, místo náročné kompilace se použije uložený bajtkód. Takováto řešení jsou poměrně oblíbená, protože získaný výkon může znamenat i několikanásobně rychlejší zpracování každého požadavku. Sdílená pamět však otevírá útočníkům další možnost, jak ovlivnit běh jiných procesů, nicméně by k ní musel útočník neprve získat přístup (prolomit bezpečnost interpretu PHP). Optimalizace webserveru pro nejvytíženější weby je velmi náročná a komplikovaná záležitost, zejména jde-li o dosažení co nejvyššího počtu současně připojených klientů. Zde se již často projevují i limity použitého operačního systému i hardwaru. Každý operační systém má např. omezení na počet současně otevřených souborů (file descriptorů). Řešení problému zvaného C10K [24], jehož cílem je umožnit webserveru obsluhovat deset tisíc spojení současně, vyžaduje detailní znalost fungování webserveru i systému, na kterém běží. Apache se pochopitelně snaží fungovat co nejefektivněji, nicméně důležitější prioritou je pro něj robustnost, modularita a bezpečnost. 17

Jiné webserverové produkty, které jsou od začátku vyvíjeny pro nejvyšší možný výkon, mohou dosahovat větší efektivity, nicméně toto vždy závisí na přesné hardwarové i softwarové konfiguraci. 18

Kapitola 4 Apache HTTP server Webový server Apache HTTP server [25] je dnes světová jednička mezi webservery a jedná se o velmi propracovaný a vyspělý systém. Svou modulární architekturou usnadňuje práci administrátorům a vývojářům webových aplikací. Tato kapitola přináší popis základních funkcí a interních struktur Apache, které jsou podstatné pro problematiku, kterou se tato práce zabývá. Celkový zevrubný popis vlastností, možností a architektury Apache je popsán v rámci The Linux Documentation Project [26]. Samotný webserver je napsán v ISO C89 (standard jazyka C z roku 1989, též zvaný ANSI C), a moduly, které jsou v něm vestavěné, také. Ale další moduly je možné psát i v jiných jazycích; jedním z nich je jazyk Perl, který je zpřístupněn skrze modul mod_perl. Ve verzi 2.4 se také objevila možnost vyvíjet rozšíření v jazyce Lua. V těchto jazycích je možné tedy nejen psát aplikace, které vyřizují požadavky (k čemuž se často využívá jazyk PHP nebo CGI skripty), ale také rozšiřovat Apache např. o další autorizační mechanismy nebo psát filtry, které umí ovlivňovat příchozí a odchozí proudy dat. Autoři současně se serverem vydávají i rozsáhlou dokumentaci [27], kde je k dispozici popis veškeré dostupné konfigurace, včetně ukázek toho, jak optimalizovat server pro výkon i zabezpečení, a řadu dalších doprovodných textů a tutoriálů. Tato dokumentace je součástí každého vydání. Co se týče konfigurace a administrace Apache, byla vydána obsáhlá kniha Apache: The Definitive Guide [28], která popisuje nejrůznější zákoutí a možné problémy a jejich řešení při instalaci a nastavování Apache. V závěru také obsahuje popis dostupného API pro psaní modulů, nicméně vnitřní funkce a interní struktury Apache jsou zde popsány pouze velmi zevrubně. Ty jsou proto důkladně rozebrány v této kapitole. 4.1 Historie Apache Historie vývoje HTTP serveru Apache začíná v roce 1995, kdy se skupina vývojářů rozhodla pokračovat na serveru zvaném httpd od NCSA (národní centrum pro superpočítačové aplikace v americkém Illinois), protože původní autor Robert McCool přestal působit v NCSA a server se přestal dále vyvíjet. Naštěstí byl projekt autorem poskytován jako public domain (v českém právu je tomu nejbližší pojem volné dílo, není to však to samé), což umožnilo, aby byl jeho kód použit jako základ webového serveru Apache. 19

Ještě v tomtéž roce byl vydán Apache 1.0, který obsahoval všechny potřebné vlastnosti, aby mohl sloužit jako plně funkční webový server. Mimo jiné umožňoval spouštět CGI skripty. Verze 1.3 měla první vydání v roce 1998 a přinesla mimo jiné možnost zavádět moduly za běhu (DSO knihovny) na většině unixových systémů, podporu pro Windows (jak řady 9x, tak NT), sjednocení konfiguračních souborů a řadu změn zlepšujících výkon webserveru. V této době Apache obsahoval velkou škálů modulů, které zajišťovaly kontrolu přístupu (mod_access, mod_auth, mod_digest), přepis URL (mod_rewrite, mod_alias), proxy služby (mod_proxy), interní informace (mod_status) a mnoho dalšího. V roce 2002 pak vyšlo první stabilní vydání z nové řady 2.0 (beta verze však byly vydávana již dva roky předtím), které přineslo velké změny v kódu Apache i v jeho modulárním API. Zavedení APR (Apache Portable Runtime) umožnilo oddělení kódu, který je závislý na konkrétní platformě, a zavedení jednotného rozhraní pro řadu úkonů, které je nutné provádět různě na různých platformách. Nový druh modulů MPM (multi-processing modules) umožňuje administrátorům vybrat, jakým způsobem bude fungovat samotné jádro Apache a vyřizování spojení a požadavků: jestli budou výkonnými jednotkami procesy nebo vlákna (na každé platformě může být efektivnější jiná metoda). Z dalších novinek je vhodné zmínit minimálně nové API pro moduly, možnost psát filtrovací moduly (pracující nad proudy dat místo nad jednotlivými požadavky), podporu IPv6 a řadu nových modulů. Řada 2.2 byla poprvé vydána v roce 2005 a o více než šest let později vyšla řada 2.4 v roce 2012. Tyto verze přinášejí mimo jiné MPM modul event (lépe řešící úzké hrdlo při velkém množství spojení) a možnost zkompilovat několik různých MPM jako moduly a určit, který se použije, až v konfiguračním souboru. Pro zaštítění projektu a organizaci vývoje vznikla v roce 1999 nezisková organizace Apache Software Foundation, která se v průběhu let rozrostla a dnes vyvíjí a podporuje více než 100 různých projektů a řadu souvisejících sub-projektů. Řízení společnosti funguje meritokratickým způsobem, ve kterém jsou privilegia a funkce přidělovány za zásluhy jednotlivých členů. 4.2 Základní operace webserveru Během spouštění Apache je nejprve načtena a naparsována konfigurace. Při této počáteční fázi je nejprve ověřována syntaktická správnost konfiguračních souborů a také jsou při ní rovnou načítány moduly pomocí direktivy LoadModule. To je nutné z toho důvodu, že tyto moduly obsahují definice potřebné pro samotné ověření syntaxe. Poté je dvakrát načtena konfigurace. První průběh nejprve testuje, zda je konfigurace platná, teprve pokud ano, spustí se načítání podruhé. Během tohoto je pro každou přítomnou konfigurační direktivu volán příslušný modul, ve kterém je definována. Následně je řízení předáno patřičnému MPM, který je zvolený v konfiguraci. Ten vytvoří sadu výkonných procesů (nebo vláken, podle typu MPM), které naslouchají na zvoleném TCP portu a čekají na spojení. Po obdržení spojení, zavolá výkonná jednotka funkci ap_process_connection, což je interní funkce, která zařídí celou obsluhu spojení. Poté, co tato funkce skončí, je spojení ukončeno a celý postup se opakuje. 20

V rámci zpracování spojení je nejprve načtena tzv. request line (první řádek požadavku), která obsahuje verzi protokolu, URL a metodu požadavku, a hlavičky zaslané klientem. Tyto informace jsou zpracovány a uloženy do struktury request_rec. Dále se zavolá funkce ap_process_request, která zařídí samotné zpracování jednotlivého požadavku. 4.3 Modularita Apache Základní vlastností, která je často zmiňovaná v souvislosti s Apachem, je jeho propracovaná modulární architektura. Kód jádra Apache obsahuje jen nutné věci pro samotný chod serveru (načítání konfigurace, čtení a zápis do socketů,... ) a podpůrné funkce pro moduly. I řada velmi běžných funkcí, které jsou přímo součástí Apache, je implementována v jednotlivých modulech: Autorizace a autentifikace a kontrola přístupu je dodávána v modulech mod_authn_core (jádro autentifikace), mod_authn_file (přístupové údaje ze souboru), mod_auth_basic (HTTP Basic autentifikace) a v řadě dalších. Modul mod_cache poskytuje modulární mechanismus umožňující kešovat výsledky prakticky libovolného požadavku. mod_dav implementuje do Apache funkci WebDAV serveru, který umožňuje klientům upravovat a spravovat soubory pomocí relativně jednoduchého rozšíření protokolu HTTP. Dobu, po kterou může probíhat zasílání požadavku, je možné omezit modulem mod_reqtimeout. CGI skripty jsou provozovány pomocí modulů mod_cgi nebo mod_cgid. Logování je zajištěno modulem mod_log_config. Apache může fungovat i jako proxy server, k tomu slouží modul mod_proxy. Bezpečnou komunikaci přes SSL/TLS poskytuje mod_ssl. Mnoho dalších funkcí je zabaleno do dalších modulů. Dokonce i implementace samotného protokol HTTP není v jádře Apache, ale v modulu, ačkoliv tento modul není úplně samostatný a také Apache nemůže fungovat bez něj. O vývoji modulů a o interním fungování Apache píše Nick Kew v knize The Apache Modules Book [29], ke které také vydal řadu doprovodných textů a ukázek [30], které demonstrují, jak lze využít robustnost Apache pro vývoj vlastního modulu. 4.4 MPM (Multi-processing modules) Jednou z nejvýraznějších změn, kterou přinesla řada Apache 2.0, bylo oddělení kódu, který zajišťuje vznik a řízení výkonných procesů, do samostatného modulu, kterému se říká multi-processing module (MPM). Takovýchto modulů bylo do Apache přidáno několik a liší se ve způsobu, jakým zajišťují paralelní zpracování 21

požadavků (procesy nebo vlákna), a také tím, jaké operační systémy podporují. Tím vznikla možnost vybrat si vhodný MPM podle potřeby. Výkon webserveru často záleží zejména na vhodně zvoleném a správně nakonfigurovaném MPM, ale nelze obecně říci, že by některý MPM byl ve všech prostředích nejrychlejší. Některé externí moduly do Apache navíc nepodporují běh ve vícevláknovém prostředí, protože jejich kód nebo některých knihoven, které používají, není tzv. thread-safe. Jedná se o způsob, jak vytvářet kód, který bude bezpečně a korektně běžet i ve více vláknech zároveň. Zejména je nutné správně ošetřit přístup ke všem globálním (sdíleným) datům a prostředkům, aby nedocházelo ke kolizím. MPM založený na vláknech je možné použít pouze pokud víme, že všechny moduly umožňují běh pod takovýmito MPM. 4.4.1 MPM prefork Modul prefork je základní MPM, který je obdobou způsobu, jak fungoval Apache ve větvi 1.3 [31]. Apache s tímto modulem běží jako množina procesů, které všechny naslouchají na zadaném portu. Tyto procesy jsou vyrobeny systémovým voláním fork a jsou vyrobeny dopředu (odtud pochází název modulu), aby byly k dispozici pro vyřizování požadavků. Poté, co proces zpracuje požadavek (resp. celé spojení), tak opět začně čekat na příchozí spojení. Tímto způsobem odpadá nutnost vytvářet nový proces pro každé spojení/požadavek. Kromě těchto výkonných procesů, které jsou spuštěny pod uživatelem se sníženými právy, běží nad nimi ještě jeden rodičovský proces (s právy uživatele root); ten hlídá, že je k dispozici dostatečné množství volných procesů. Konfiguračními direktivami MinSpareServers a MaxSpareServers lze nastavit minimální a maximální počet volných procesů. Rodičovský proces poté periodicky kontroluje, kolik výkonných procesů je nečinných, a případně vyrobí nový nebo nějakému procesu zašle požadavek na ukončení přes tzv. pipe of death, což je mechanismus, jak bezpečně ukončit (graceful shutdown) výkonný proces. Ukončení se tímto způsobem provede až poté, co proces dokončí zpracování aktuálního spojení. Výhodou jednovláknových procesů je izolace zpracovávaných požadavků: pokud při zpracování proces spadne nebo bude mít memory leak (alokovaná paměť, která se kvůli chybě nikdy nedealokuje), je možné jednotlivý proces ukončit a neovlivní to funkci ostatních procesů. Někde je také nutné využívat knihovnu či modul, který není thread-safe; v takovém případě není vůbec možné použít vícevláknové MPM. 4.4.2 MPM worker Alternativní MPM jménem worker je k dispozici v Apachi od verze 2.0. Jedná se o víceprocesový a zároveň vícevláknový server, přičemž je možné konfigurovat jak počet běžících procesů, tak i počty vláken v procesech. Každé vlákno zpracovává jedno aktivní spojení, ale po jeho ukončení čeká na další příchozí spojení. Každý výkonný proces si vytvoří konstantní počet vláken a jedno hlavní vlákno, které přijímá spojení a rozděluje je ostatním vláknům. Stejně jako u preforku kontroluje rodičovský proces počty procesů, aby jich nebylo příliš málo nebo moc (podle aktuální zátěže), nicméně toto rozhodování se provádí na základě počtu nečinných vláken. K nastavování minimálního 22