<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Aiv&#039;s dev blog &#187; suexec</title>
	<atom:link href="http://aiv-dev.info/tag/suexec/feed/" rel="self" type="application/rss+xml" />
	<link>http://aiv-dev.info</link>
	<description>Ciekawostki programistyczne i tematy związane z bezpieczeństwem</description>
	<lastBuildDate>Sat, 09 Jan 2010 16:48:08 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Konfiguracja Apache + FastCGI + SuExec + PHP 4/5 + kilka innych rozwiązań</title>
		<link>http://aiv-dev.info/2007/12/30/konfiguracja-apache-fastcgi-suexec-php-4-5-kilka-innych-rozwiazan/</link>
		<comments>http://aiv-dev.info/2007/12/30/konfiguracja-apache-fastcgi-suexec-php-4-5-kilka-innych-rozwiazan/#comments</comments>
		<pubDate>Sun, 30 Dec 2007 15:45:38 +0000</pubDate>
		<dc:creator>Mariusz Dalewski</dc:creator>
				<category><![CDATA[Administracja]]></category>
		<category><![CDATA[Bezpieczeństwo]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[fastcgi]]></category>
		<category><![CDATA[php.ini]]></category>
		<category><![CDATA[php4]]></category>
		<category><![CDATA[php5]]></category>
		<category><![CDATA[suexec]]></category>

		<guid isPermaLink="false">http://aiv-dev.info/2007/12/30/konfiguracja-apache-fastcgi-suexec-php-45-kilka-innych-rozwiazan/</guid>
		<description><![CDATA[Postanowiłem na własne potrzeby stworzyć pewien szablon konfiguracji PHP opartej o Apache. Podstawowym celem było bezpieczeństwo rozwiązania, a jak udało mi się to zrealizować &#8211; życie pokaże. W prezentowanych przykładach pominąłem większość parametrów konfiguracyjnych, a więc podczas tworzenia własnego środowiska na bazie niniejszego artykuły zalecam dostosowanie ich do własnych potrzeb.
Na potrzeby niniejszej konfiguracji użyłem:

Linux Slackware [...]]]></description>
		    		<content:encoded><![CDATA[<p>Postanowiłem na własne potrzeby stworzyć pewien szablon konfiguracji PHP opartej o Apache. Podstawowym celem było bezpieczeństwo rozwiązania, a jak udało mi się to zrealizować &#8211; życie pokaże. W prezentowanych przykładach pominąłem większość parametrów konfiguracyjnych, a więc podczas tworzenia własnego środowiska na bazie niniejszego artykuły zalecam dostosowanie ich do własnych potrzeb.</p>
<h4>Na potrzeby niniejszej konfiguracji użyłem:</h4>
<ul>
<li>Linux Slackware w wersji 12. Starałem się nie używać ustawień i pakietów pochodzących z dystrybucji, żeby rozwiązanie było jak najbardziej uniwersalne</li>
<li>Apache w wersji 2.2.6</li>
<li>FastCGI w wersji 2.4.6</li>
<li>PHP w wersji 4.4.7 i 5.2.5</li>
</ul>
<h4>Przyjąłem również kilka założeń:</h4>
<ul>
<li>Skrypty PHP powinny być uruchamiane w zamkniętym środowisku (np: chroot() albo open_basedir())</li>
<li>Skrypty PHP powinny być uruchamiane z uprawnieniami właściciela pliku/virtualhosta</li>
<li>Każdy użytkownik powinien mieć indywidualny folder tmp i folder przechowywania plików sesji</li>
<li>Każdy użytkownik sam może wybrać wersji PHP</li>
<li>Dla każdego virtualhosta powinien istnieć oddzielny plik php.ini</li>
<li>Tworzone rozwiązanie powinno być jak najbardziej uniwersalne. Jednocześnie powinno oferować administratorowi wygodę zarządzania</li>
</ul>
<p><!--feed--><span id="more-14"></span></p>
<h3>Instalacja Apache:</h3>
<p>Apache wraz z modułem suexec potrafi uruchamiać skrypty CGI z uprawnieniami użytkownika. Model bezpieczeństwa suexec <strong>wymaga deklarowania zmiennych środowiskowych</strong>, które mają być przekazywane do CGI. Większość zmiennych środowiskowych np.: REQUEST_URL, DOCUMENT_ROOT itp. są wpisane na stałe do pliku support/suexec.c, jednak <strong>brakuje tam zmiennych dla PHP</strong>, które pomagają mu współpracować z modułem FastCGI. Musimy je ręcznie dopisać, a więc otwieramy plik <strong>support/suexec.c</strong> w ulubionym edytorze tekstowym i znajdujemy kod:</p>
<textarea name="code" class="c:firstline[94]" cols="50" rows="10">
static const char *const safe_env_lst[] =
{
/* variable name starts with */
"HTTP_",
"SSL_",

/* variable name is */
"AUTH_TYPE=",
"CONTENT_LENGTH=",
"CONTENT_TYPE=",
"DATE_GMT=",
"DATE_LOCAL=",
"DOCUMENT_NAME=",
"DOCUMENT_PATH_INFO=",
"DOCUMENT_ROOT=",
</textarea>
<p>Dopisujemy przed linijką zawierającą AUTH_TYPE:</p>
<textarea name="code" class="c:nogutter" cols="50" rows="10">
"PHP_FCGI_MAX_REQUEST=",
"PHP_FCGI_CHILDREN=",
</textarea>
<p>Plik wynikowy powinien wyglądać następująco:</p>
<textarea name="code" class="c:firstline[94]" cols="50" rows="10">
static const char *const safe_env_lst[] =
{
/* variable name starts with */
"HTTP_",
"SSL_",

/* variable name is */
"PHP_FCGI_MAX_REQUEST=",
"PHP_FCGI_CHILDREN=",
"AUTH_TYPE=",
"CONTENT_LENGTH=",
"CONTENT_TYPE=",
"DATE_GMT=",
"DATE_LOCAL=",
"DOCUMENT_NAME=",
"DOCUMENT_PATH_INFO=",
"DOCUMENT_ROOT=",
</textarea>
<p>Dzięki wykonanej modyfikacji suexec będzie <strong>przekazywał zmienne środowiskowe</strong>, które ustawi FastCGI, do wrappera PHP (w dalszej części artykuły opisze obie zmienne i dlaczego trzeba było wprowadzić tą poprawkę).</p>
<p>Teraz możemy przystąpić do rzeczywistej konfiguracji Apache. Uruchamiamy komendę:</p>
<textarea name="code" class="general:nogutter" cols="50" rows="10">
./configure --enable-so  --with-suexec-caller=www --with-suexec-docroot=/var/www --with-suexec-logfile=/var/log/suexec --enable-suexec=shared --enable-cgi=shared --with-suexec-bin=/usr/local/apache2/sbin/suexec
</textarea>
<h4>Opis parametrów:</h4>
<ul>
<li><strong>&#8211;enable-so</strong>: włączenie mechanizmu DSO</li>
<li><strong>&#8211;with-suexec-caller</strong>: użytkownik z którego będzie wywoływany suexec. Należy tutaj wpisać nazwę użytkownika na którym działa Apache</li>
<li><strong>&#8211;with-suexec-docroot</strong>: ścieżka w której znajdują się wszystkie skrypty PHP uruchamiane przez suexec</li>
<li><strong>&#8211;with-suexec-logfile</strong>: plik do którego suexec będzie logował. Należy pamiętać o utworzeniu takiego pliku i nadaniu mu uprawnień do zapisu dla użytkownika na którym działa Apache. Należy mieć też na uwadze konieczność rotowania tego pliku &#8211; Apache się tym nie zajmuje</li>
<li><strong>&#8211;enable-suexec</strong>: włączenie mechanizmu suexec</li>
<li><strong>&#8211;enable-cgi</strong>:włącza obsługę CGI &#8211; niezbędne do konfiguracji PHP jako CGI</li>
<li><strong>&#8211;with-suexec-bin</strong>: ścieżka do pliku suexec w naszym systemie. Plik ten może znajdować się w dowolnym miejscu</li>
</ul>
<p>Jeżeli nie dodałeś żadnego layoutu ustawień (&#8211;enable-layout=LAYOUT) podczas konfigurowania Apache, pliki zostaną <strong>umieszczone w katalogu /usr/local/apache2</strong>. Jeżeli zmieniłeś layout, pamiętaj o zmianie ścieżki do pliku suexec (&#8211;with-suexec-bin).</p>
<textarea name="code" class="general:nogutter" cols="50" rows="10">
make
make install
</textarea>
<h3>Instalacja FastCGI:</h3>
<p>Konfiguracja FastCGI sprowadza się do wykonywania instrukcji instalacyjnych z pliku <strong>INSTALL.AP2</strong>. Należy pamiętać o zmianie ścieżki <strong>top_dir</strong> w przypadku innej konfiguracji Apache. We wskazanym katalogu powinien się znaleźć plik <strong>build/special.mk</strong>:</p>
<textarea name="code" class="general:nogutter" cols="50" rows="10">
cp Makefile.AP2 Makefile
make top_dir=/usr/local/apache2
make install
</textarea>
<h3>Instalacja PHP:</h3>
<p>Instalacja obu wersji PHP przebiega podobnie dlatego opiszę tylko jedną wersję w tym miejscu. W przypadku PHP 4 zalecał bym tylko zmianę prefixu na /usr/local/php4. Dalsza część artykułu zawiera konfiguracje dla systemu z obiema wersjami PHP.</p>
<textarea name="code" class="general:nogutter" cols="50" rows="10">
./configure --prefix=/usr/local/php5 --enable-force-cgi-redirect --enable-fastcgi
</textarea>
<p>Celowo nie dodawałem tutaj parametru –sysconfdir, który wskazuje na miejsce szukania domyślnego pliku php.ini. Będę używał parametru -c do wskazania pliku php.ini. Dowiedz się więcej o <a href="/2007/12/29/kolejnosc-wczytywania-plikow-phpini/">kolejności ładowania plików php.ini</a> z mojego artykułu.</p>
<h4>Opis parametrów:</h4>
<ul>
<li><strong>&#8211;prefix</strong>: prefix instalacji ustawiłem na /usr/local/php5 gdyż równolegle będziemy instalować php4 i dobrze by było gdyby dwie wersji nie wchodziły sobie w drogę</li>
<li><strong>&#8211;enable-force-cgi-redirect</strong>: parametr ten zabezpiecza przed wywołaniem skryptu PHP poprzez link bezpośredni do skryptu FastCGI w folderze fcgi. Skrypt PHP zostanie wykonany tylko i wyłącznie jeżeli odwołanie do parsera zostało wykonane przez Apache</li>
<li><strong>&#8211;enable-fastcgi</strong>: włączenie obsługi FastCGI w parserze PHP</li>
</ul>
<p>Zanim wykonasz poniższe komendy utwórz katalog /usr/local/php5.</p>
<textarea name="code" class="general:nogutter" cols="50" rows="10">
make
make install
</textarea>
<p>W tym momencie zakończyliśmy instalacje i podstawową konfigurację niezbędnego programowania. Przystąpmy zatem do dalszej konfiguracji.</p>
<h3>Konfiguracja Apache:</h3>
<p>Plik konfiguracyjny Apache (<strong>httpd.conf</strong>) powinien zawierać między innymi takie ustawienia:</p>
<textarea name="code" class="general:nogutter" cols="50" rows="10">
LoadModule suexec_module modules/mod_suexec.so
LoadModule cgi_module modules/mod_cgi.so
LoadModule fastcgi_module modules/mod_fastcgi.so

&lt;IfModule mod_fastcgi.c&gt;
FastCgiWrapper /usr/sbin/suexec
FastCgiConfig \
-initial-env PHP_FCGI_CHILDREN=1 \
-initial-env PHP_FCGI_MAX_REQUESTS=5000 \
-singleThreshold 90 \
-killInterval 300 \
-autoUpdate \
-idle-timeout 240 \
-pass-header HTTP_AUTHORIZATION
&lt;/IfModule&gt;
</textarea>
<h4>Opis parametrów:</h4>
<ul>
<li><strong>FastCgiWrapper</strong>: w tym miejscu deklarujemy wrapper dla FastCGI. Zamiast suexec możemy użyć np. cgiwrap albo sbox. Jeżeli chcemy użyć tego samego wrapper co Apache możemy ustawić tą opcję na &#8220;On&#8221;</li>
<li><strong>FastCgiConfig</strong>: deklarujemy w jaki sposób ma się zachowywać FastCGI</li>
<li><strong>-initial-env PHP_FCGI_CHILDREN=1</strong>: Ustawia zmienną środowiskową PHP_FCGI_CHILDREN która poprzez wrapper (np.: suexec) przekazujemy do PHP. Jeżeli nie zmodyfikowali byśmy źródeł suexec , zmienna ta została by wycięta. PHP_FCGI_CHILDREN określa ile procesów potomnych ma obsługiwać żądania PHP dla jednego virtualhosta</li>
<li><strong>-initial-env PHP_FCGI_MAX_REQUEST=5000</strong>: Zmienna ta określa maksymalną ilość żądań po których dany proces zostanie zakończony i uruchomiony w razie potrzeby od nowa</li>
<li><strong>-singleThreshold 90</strong>: Parametr przyjmuje wartości liczbowe od 0 do 100. FastCGI na tej podstawie określa czy dany proces ma być utrzymywany (wartość bliższa 1) czy zabity (bliżej 100) jeżeli nie jest już wykorzystywany. Jeżeli zależy Ci się na oszczędności pamięci ustaw ten parametr bliżej 100. Ustawienie na 0 zapobiegnie wyłączaniu ostatniego procesu potomnego</li>
<li><strong>-killInterval 300</strong>: Wartość parametru w sekundach, określa po jakim czasie bezczynności proces ma zostać zabity</li>
<li><strong>-autoUpdate</strong>: Powoduje sprawdzanie daty skryptów FastCGI. Jeżeli któryś z nich zostanie zaktualizowany, FastCGI zabije proces i uruchomi go od nowa</li>
<li><strong>-idle-timeout 240</strong>: Czas w sekundach który ma skrypt PHP na uruchomienie i rozpoczęcie zwracania wyników użytkownikowi</li>
<li><strong>-pass-header HTTP_AUTHORIZATION</strong>: Przekazania nagłówków uwierzytelniania HTTP do CGI. Standardowo nagłówki te nie są przekazywane</li>
</ul>
<p>Przyjąłem, że każdy virtualhost posiada swój katalog w /var/www.  Struktura prezentuje się następująco:<br />
/var/www/host1.example.com<br />
/var/www/host1.example.com/htdocs – główny folder dostępny przez http<br />
/var/www/host1.example.com/htdocs/fcgi – folder ze skryptami FastCGI<br />
/var/www/host1.example.com/tmp – folder przeznaczony na pliki sesji i pliki tymczasowe</p>
<h3>Konfiguracja virtualhosta:</h3>
<textarea name="code" class="general:nogutter" cols="50" rows="10">
&lt;VirtualHost *:80&gt;
SuexecUserGroup v1 v1

&lt;Location /fcgi/php4&gt;
SetHandler fastcgi-script
Options +ExecCGI
&lt;/Location&gt;

&lt;Location /fcgi/php5&gt;
SetHandler fastcgi-script
Options +ExecCGI
&lt;/Location&gt;

&lt;Directory /var/www/host1.example.com/htdocs/fcgi &gt;
AllowOverride None
Options None
Order allow,deny
Allow from all
&lt;/Directory&gt;

AddHandler php5-fastcgi .php
Action php5-fastcgi /fcgi/php5
Action php4-fastcgi /fcgi/php4

AddType application/x-httpd-php .php

DocumentRoot /var/www/host1.example.com /htdocs/
ServerName host1.example.com
ErrorLog /var/log/httpd/host1.example.com-error_log
CustomLog /var/log/httpd/host1.example.com-access_log common
&lt;/VirtualHost&gt;
</textarea>
<h4>Opis parametrów:</h4>
<ul>
<li><strong>SuexecUserGroup v1 v1</strong>: określa systemowego użytkownika i grupę na którą suexec ma przenieść uprawnienia</li>
<li><strong>&lt;Location /fcgi/php5&gt;&#8230;&lt;/Location&gt;</strong>: Zarejestrowanie pliku /fcgi/php5 jako skryptu FastCGI</li>
<li><strong>&lt;Location /fcgi/php4&gt;&#8230;&lt;/Location&gt;</strong>: Jw. tylko, że dla pliku /fcgi/php4</li>
<li><strong>&lt;Directory&gt;…&lt;/Directory&gt;</strong>: Ustawienia katalogu fcgi. Należy tutaj szczególną uwagę zwrócić na &#8220;Options None&#8221;. Zabezpiecza to przed możliwością uruchamiania programów niż zadeklarowane w &lt;Location &#8230;&gt;. Dodatkowo opcja &#8220;AllowOverride None&#8221; zabezpiecza przed możliwością zmiany tych ustawień z poziomu pliku .htaccess</li>
<li><strong>AddHandler php5-fastcgi .php</strong>: Ustawia domyślny interpretator dla plików .php na PHP 5. Gdyby użytkownik chciał zmienić wersje PHP na inna wystarczy, że sam we własnym zakresie stworzy plik .htaccess i wpisze do niego AddHandler php4-fastcgi .php</li>
<li><strong>Action php5-fastcgi /fcgi/php5</strong>: Deklaracja skryptu FastCGI dla PHP 5</li>
<li><strong>Action php4-fastcgi /fcgi/php4</strong>: Deklaracja skryptu FastCGI na PHP 5</li>
</ul>
<p>Trzy opisane na końcu parametry można <strong>umieścić poza sekcją</strong> &lt;VirtualHost&gt;&#8230;&lt;/VirtualHost&gt; czyniąc  z nich <strong>ustawienia globalne</strong> dla serwera.</p>
<p>Teraz utworzymy skrypty FastCGI zadeklarowane w konfiguracji Apache. Skrypty te musimy utworzyć <strong>dla każdego virtualhosta</strong> w katalogu htdocs/fcgi.<br />
Dla PHP 5 tworzymy plik htdocs/fcgi/php5:</p>
<textarea name="code" class="general:nogutter" cols="50" rows="10">
#!/bin/bash
exec /usr/local/php5/bin/php-cgi -c php5.ini
</textarea>
<p>Dla PHP tworzymy plik htdocs/fcgi/php4:</p>
<textarea name="code" class="general:nogutter" cols="50" rows="10">
#!/bin/bash
exec /usr/local/php4/bin/php -c php4.ini
</textarea>
<p>Niektórzy zadadzą sobie teraz pytanie &#8220;Po co dodawać każdemu katalog fcgi razem ze skryptami skoro mogę zrobić jeden katalog i podlinkować go każdemu?&#8221;.</p>
<p>Odpowiedź leży w źródłach suexec, które edytowaliśmy na początku. Model bezpieczeństwa suexec jest bardzo restrykcyjny i dokładnie porównuje uprawnienia uruchamianych programów razem z folderami virtualhosta. Jeżeli chodź jeden z testów nie będzie zgodny, skrypt nie zostanie uruchomiony. Rozwiązaniem jest modyfikacja źródeł suexec albo rozwiązanie problemu poprzez kopiowanie skryptów FastCGI do każdego virtualhosta. <strong>Pamiętaj o zmianie właściciela</strong> plików php4 i php5.</p>
<p>W tym miejscu powinienem powrócić jeszcze do modyfikacji suexec, którą wykonaliśmy na początku. Nic nie stało na przeszkodzie żebyśmy dopisali do utworzonych przed chwilą skryptów export zmiennych globalnych np.:</p>
<textarea name="code" class="general:nogutter" cols="50" rows="10">
#!/bin/bash
export PHP_FCGI_CHILDREN 1
export PHP_FCGI_MAX_REQUESTS 5000
exec /usr/local/php5/bin/php-cgi -c php5.ini
</textarea>
<p>Modyfikację tą wprowadzaliśmy jednak, żeby istniała możliwość <strong>ustawienia tych parametrów globalnie</strong>. Jeżeli jeden z virtualhostow wymaga innej konfiguracji to możemy zmodyfikować te wartości właśnie poprzez export jak na ww. przykładzie.</p>
<h3>Pliki konfiguracyjne php.ini:</h3>
<p>Żeby cała ta konfiguracja zdała egzamin musimy w przygotować indywidualne pliki php.ini dla każdego virtualhosta. W przypadku PHP 5 sprawa jest odrobinę ułatwiona. Temat ten opisałem w artykule &#8220;<a href="/2007/12/29/uproszczenie-w-konfiguracji-php-5-per-virtualhost/">Uproszczenie w konfiguracji PHP 5 per virtualhost</a>&#8220;.W pliku konfiguracyjnym obu wersji PHP <strong>powinny</strong> się znaleźć:</p>
<textarea name="code" class="general:nogutter" cols="50" rows="10">
open_basedir = "/var/www/host1.example.com:/usr/local/php5"
disable_functions = proc_open, popen, disk_free_space, diskfreespace, leak, exec, system, shell_exec, passthru, dl
expose_php = Off
log_errors = On
error_log = "/var/www/host1.example.com /php_error"
register_globals = Off
enable_dl = Off
upload_tmp_dir = "/var/www/host1.example.com /tmp"
sendmail_path = "/usr/sibn/sendmail -t -i -f info@host1.example.com"
session.save_path = "/var/www/host1.example.com /tmp"
</textarea>
<h3>Finalizacja:</h3>
<p>Na koniec pozostaje nam kilka <strong>problemów do rozwiązania</strong>, a mianowicie:</p>
<ul>
<li>użytkownik może zmodyfikować zawartość skryptów znajdujących się w htdocs/fcgi, a co za tym idzie, dajemy mu dostęp do powłoki systemu, czego z pewnością większość z Was wolała by uniknąć</li>
<li>użytkownik może zmienić/skasować plik php.ini. Ma wtedy dostęp do modyfikacji spersonalizowanych wartości open_basedir, error_log, session.save_path, disable_functions itp.</li>
</ul>
<p>Żeby rozwiązać te problemy, należało by <strong>zabrać użytkownikowi możliwość edycji plików</strong> w katalogu htdocs/fcgi. Gdy zabierzemy mu uprawnienia poprzez zmianę właściciela, suexec bardzo szybko przypomni nam o tym fakcie. Rozwiązanie jakie znalazłem niestety nie jest eleganckie, ale za to jest skuteczne.</p>
<p>Użytkownicy systemu plików ext2/3 mogą nadać atrybut +i dla katalogu <strong>htdocs/fcgi</strong> poprzez <strong>chattr +i fcgi</strong>. Uniemożliwi to wprowadzanie zmian na folderze fcgi (razem z jego zawartością) dla wszystkich użytkowników systemu. Tak założone atrybut +i zdejmuje tylko i wyłącznie root.</p>
<h3>Change log artykułu:</h3>
<p>Będę się starał uaktualniać ten artykuł, a więc w tym miejscu opisze przyszłe zmiany.<br />
25/02/2008 19:38 &#8211; Usunięcie niepoprawnych spacji z konfiguracji VirtualHost.<br />
04/02/2008 17:41 &#8211; Zmieniłem nazwę &#8220;apache2.conf&#8221; na &#8220;httpd.conf&#8221; celem poprawienia zgodności z domyślną konfiguracją Apache.<br />
30/01/2008 20:28 &#8211; Zmiana &lt;IfModule&gt; na &lt;/IfModule&gt; w konfiguracji Apache.<br />
25/01/2008 12:26 &#8211; Poprawka związana z błędną nazwa foldera w przykładowej konfiguracji Apache. Zamienione &#8220;fcgi-bin&#8221; na &#8220;fcgi&#8221;.<br />
30/12/2007 16:45 &#8211; Publikacja pierwszej wersji</p>
]]></content:encoded>
	    			<wfw:commentRss>http://aiv-dev.info/2007/12/30/konfiguracja-apache-fastcgi-suexec-php-4-5-kilka-innych-rozwiazan/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
	</channel>
</rss>
