A própria natureza de correr sites dinâmicos num servidor constitui um projecto arriscado. Os métodos aqui discutidos diminuem o risco de invasão e reduzem os danos causados por uma brecha. Como sempre, devemos estar informados sobre novas vulnerabilidades que vão surgindo, aplicando os patches respectivos.
O PHP pode ser instalado num servidor como
interpretador CGI ou
módulo Apache. Cada um destes métodos tem vantagens e desvantagens.
No primeiro caso, é possível ter processos diferentes a correr para utilizadores diferentes em
virtual hosts diferentes, usando o suEXEC do Apache. No entanto, este método de instalação pode ser lento e é fértil em riscos de segurança, quando mal configurado.
Em alternativa, pode instalar-se o PHP como módulo Apache, que é o método em que nos vamos focar neste artigo. Neste caso, pode-se ainda optar por compilar o PHP como módulo estático ou dinâmico. O estático tem como vantagem, uma melhor performance, mas quando se decidir fazer um upgrade, tem que se recompilar tanto o Apache como o PHP. Com o dinâmico, perde-se alguma performance, é necessário ter o Apache compilado com suporte para módulos dinâmicos, fazendo uso do módulo mod_so, mas os upgrades de PHP são bem mais simples. A escolha deve depender das necessidades particulares de cada um - especialmente a importância da performance versus conveniência de um fácil upgrade.
Módulo estático
É necessário compilar o PHP antes da compilação do Apache com os comandos:
./configure --with-mysql=/usr/local/mysql --with-apache=/path/to/apache_source --enable-safe-mode
make
su
make install
Copia-se então o ficheiro
dir_apache/mod_security.c para o directório
src/modules/extra do Apache, compilando-se este de seguida, seguindo os passos tradicionais (que não são do âmbito deste artigo), adicionando as seguintes opções:
--activate-module=src/modules/extra/mod_security --enable-module=security --activate-module=src/modules/php4/libphp4.a.
Módulo dinâmico
Instala-se primeiro o Apache e depois compila-se o PHP com os seguintes comandos:
./configure --with-mysql=/usr/local/mysql --with-apxs=/usr/sbin/apxs --enable-safe-mode
make
su
make install
Para instalar o
mod_security como módulo dinâmico, extraem-se as sources e corre-se o comando
apxs -cia mod_security.c para instalar.
Seja qual for o método de instalação escolhido, devem-se activar as opções estritamente necessárias, porque incluir mais funcionalidades significa aumentar o risco de vulnerabilidades. Adicionalmente, em ambiente multi-utilizadores, é recomendável activar o
Safe Mode com
-enable-safe-mode.
Configuração do Apache
Adicionam-se as seguintes linhas ao httpd.conf para activar o PHP:
LoadModule php4_module libexec/libphp4.so
AddModule mod_php4.c
AddType application/x-httpd-php .php
AddType application/x-httpd-php .php3
AddType application/x-httpd-php .inc
AddType application/x-httpd-php .class
As directivas AddType asseguram que todos os ficheiros com extensões .php, .php3, .inc, e .class são processados como scripts PHP. Muitos programadores usam *.class e *.inc como nomes de ficheiros externos incluídos nos seus scripts. Sem estas directivas, estes ficheiros seriam mostrados como texto puro no browser, revelando potencialmente passwords ou outros dados sensíveis.
Outra forma de conseguir o mesmo efeito, é usar a directiva Files para negar o acesso a determinados ficheiros. Por exemplo, as linhas
Order allow,deny
Deny from all
Satisfy All
negam o acesso a todos os ficheiros cujo nome termine em .inc ou .inc.php, estando apenas acessíveis usando include() ou require() num script.
Se não se quiser que seja óbvio o facto de se estar a usar PHP num servidor, pode-se usar uma extensão diferente para os scripts. Usando
AddType application/x-httpd-php .dhtml teríamos o Apache a interpretar todos os ficheiros com extensão .dhtml como scripts PHP. Ainda assim, esta é uma medida um pouco superficial, pois há outras formas de se descobrir que um servidor está a correr PHP.
Defesa contra injection com mod_security
O
mod_security é um motor de detecção e prevenção de intrusão para aplicações Web que operam como módulo Apache. Todos os GET's e POST's são verificados e aqueles considerados maliciosos são simplesmente rejeitados de acordo com a configuração existente.
Para activar este módulo, adicionam-se as seguintes linhas ao ficheiro httpd.conf:
LoadModule security_module libexec/mod_security.so
AddModule mod_security.c
Para configurá-lo para monitorizar pedidos GET e POST, adicionam-se as linhas:
# Ligar ou desligar o filtro: On or Off
SecFilterEngine On
# Verificar codificação do URL
SecFilterCheckURLEncoding On
# Verificar codificação Unicode
SecFilterCheckUnicodeEncoding On
# Permitir apenas bytes de um intervalo
SecFilterForceByteRange 0 255
# Guardar no log apenas actividades suspeitas
SecAuditEngine RelevantOnly
# O nome do ficheiro de log
SecAuditLog logs/audit_log
# Colocar o nível de debug no mínimo
SecFilterDebugLog logs/modsec_debug_log
SecFilterDebugLevel 0
# Activar a monitorização de POST
SecFilterScanPOST On
# Por defeito, apresentar ERRO 500
# nas tentativas maliciosa
SecFilterDefaultAction "deny,log,status:500"
Esta é a configuração mais básica mas já proporciona sérias vantagens:
- Remove //;
- Remove ./;
- Faz o decoding dos URL's;
- Substitui bytes nulos (%00) por espaços;
- Valida a codificação dos URL's;
- Valida a codificação unicode;
- Verifica o intervalo de bytes.
Além destas medidas, queremos usar o
mod_security para prevenir ataques por
SQL injection e
cross-site scripting (XSS). Para o conseguirmos, basta adicionarmos as seguintes linhas:
SecFilter "\\.\\./"
SecFilter "<(.|\\n)+>"
SecFilter "'"
SecFilter "\""
A primeira linha previne o acesso a ficheiros fora do directório do site. A segunda detecta < e >, fazendo com que o servidor rejeite pedidos com tags HTML e ajudando na protecção contra os ataques XSS. As últimas duas linhas filtram as plicas e as aspas respectivamente, dificultando os ataques por
SQL injection.
Usando o Safe mode
Uma das maiores preocupações ao nível da segurança do PHP num ambiente multi-utilizador é o facto dos scripts correrem sob o ID do utilizador do servidor. Isto não só significa que os utilizadores PHP têm acesso a qualquer recurso a que o servidor tenha acesso, como tdos os scripts PHP têm acesso entre si, uma vez que todos operam com o mesmo ID de utilizador.
Em termos de arquitectura, este problema é melhor resolvido ao nível do sistema operativo mas, embora existeam várias soluções, não há nenhuma completamente satisfatória. Assim, os responsáveis pelo desenvolvimento do PHP inventaram o
Safe Mode.
O
Safe Mode assegura que qualquer ficheiro que é acedido por um script, é propriedade do propritário do dito script. Para activar o
Safe Mode, deve compilar-se o PHP como acima descrito e depois activar no php.ini, colocando a variável
safe_mode a
on. Quando está ligado, uma versão ligeiramente mais relaxada pode ser activada usando safe_mode_gid=on, que utiliza o grupo como elemento de comparação nos ficheiros que estão a ser acedidos.
Existem algumas opções a considerar quando se configura o
Safe Mode. As mais importates são:
safe_mode_exec_dir = /some/dir
-- As chamadas a funções que executam ficheiros binários como o system() só conseguirão correr aqueles que estiverem no directório especificado;
safe_mode_allowed_env_vars = PHP_
-- Os utilizadores só poderão iniciar
environment variables com o prefixo PHP_. Este prefixo pode ser qualquer outra coisa, ate mesmo vários valores separados por vírgulas. No entanto, não se deve deixar em branco, uma vez que tal permitiria aos utilizadores iniciar qualquer
environment variable.
Outras configurações PHP
Para além do
Safe Mode existem outras opções no php.ini cuja configuração pode fazer a diferença ao nível da segurança:
open_basedir = /some/dir
-- limita os ficheiros que o PHP pode abrir e ler ao directório especificado. Usando . como directório, limita-se o PHP ao directório em que o script está. Pode especificar-se directórios múltiplos separados por ; (ponto e vírgula). O valor por defeito desta opção permite ao PHP aceder a qualquer directório.
disable_functions = function1,function2
-- permite ao administrador proibir o uso de funções específicas, que devem ser listadas por nome e separadas por vírgula.
expose_php = Off
-- Normalmente o PHP mostra que está instalado no servidor, adicionando headers extra. Desactivando esta opção, isso deixa de acontecer.
display_errors = Off
-- Colocando esta opção em Off evita que o PHP mostre eventuais erros de execução, que poderiam revelar informações importantes de configuração do servidor, como paths e estrutura do acesso a base de dados.
log_errors = On
-- Para logar os erros escondidos na opção anterior para um ficheiro
error_log = /var/log/php_errors
-- Para definir o ficheiro a ser uado na opção anterior.
register_globals = Off
-- evita que variáveis
ENVIRONMENT, GET, POST, Cookie, e
Built-in sejam registadas como globais. Se estes valores forem globais, a programação é bastante mais fácil mas aumenta o risco de segurança, caso o código não esteja bem cuidado.