Não sei de cabeça a linguagem markdown, então esse editor facilita muito na hora de escrever os README.md =)
Categoria: apache
Limitando tentativas de login/acesso via mod_security
Desafio do dia:
Bloquear tentativas excessivas de post em um formulário sem ser através da programação do sistema, pois persistência das tentativas em banco, por exemplo, seria muito pesado.
Esta dica também é útil para sistemas com código-fonte fechado que rodam em ambiente apache.
Num cenário hipotético, vamos considerar que:
- O processamento do formulário seja enviado via POST para o arquivo /login.php
- O limite de tentativas consecutivas será 5
Para tal, vamos editar o vhost do domínio em questão (ex: /etc/apache2/sites-enabled/000-default) e adicionar as seguintes linhas:
SecAction phase:1,id:109,initcol:ip=%{REMOTE_ADDR},nolog SecRule REQUEST_FILENAME "/login.php$" "chain,nolog,phase:1,id:110,setvar:ip.ddos_login=+1,deprecatevar:ip.ddos_login=5/10" SecRule REQUEST_METHOD "POST" SecRule REQUEST_FILENAME "/login.php$" "chain,id:111,msg:'Possible Brute Force Attack',deny,status:509" SecRule REQUEST_METHOD "POST" "chain" SecRule IP:DDOS_LOGIN "@gt 5" ErrorDocument 509 "Rate Limit Exceeded"
Explicando o funcionamento:
A primeira regra, cria um objeto chamado ip, que será único para cada REMOTE_ADDR (variável de ambiente do apache, que recebe o IP de conexão).
O bloco de regras a seguir, é uma chain do modsecurity, que, para cada POST no /login.php, incrementa um contador interno chamado ip.ddos_login
O terceiro bloco de regras é uma segunda chain que, quando o contador ip.ddos_login for maior do que 5, e a requisição for um POST em login.php, ira forçar o apache a devolver o http status 509 (Rate Limit Exceeded)
A última linha, serve somente para que seja exibido uma mensagem fixa quando browser do usuário recebe o status http 509, pode ser também o path para um arquivo html.
Instalar PHP5.3 no ubuntu 14.04
Esta dica teoricamente funciona também nas versões mais recentes do ubuntu.
Estes dias um antigo cliente meu entrou em contato solicitando a árdua tarefa de instalar o PHP 5.3 na última versão LTS do ubuntu (no momento em que escrevo é a 14.04).
Meu primeiro pensamento, foi baixar o tarball e compilar no servidor. Depois de mais de uma hora resolvendo dependências de bibliotecas, me deparo com erro na hora do make que eram basicamente questões relativas a versão de compilador, sendo praticamente impossível resolver (e olha que tentei).
Logo surgiu a ideia de buscar algum PPA que contenha esta versão, que também foi em vão, pois descobri que mesmo os repositórios que, em alguns artigos na internet diziam que continham esta versão do PHP, já haviam atualizado para as mais novas.
Quando tudo estava perdido, eis que surge uma ideia muito maluca. E se eu adicionasse os repositórios do ubuntu 12.04, deveria haver algum jeito de forçar o apt a utilizar pacotes de um determinado repositório.
Então, sem mais delongas, segue a receita de bolo:
Primeiro vamos criar um arquivo contendo os repositórios do ubuntu precise (12.04)
/etc/apt/sources.list.d/precise.list
deb http://mirror.rackspace.com/ubuntu/ precise main restricted deb-src http://mirror.rackspace.com/ubuntu/ precise main restricted deb http://mirror.rackspace.com/ubuntu/ precise-updates main restricted deb-src http://mirror.rackspace.com/ubuntu/ precise-updates main restricted deb http://mirror.rackspace.com/ubuntu/ precise universe deb-src http://mirror.rackspace.com/ubuntu/ precise universe deb http://mirror.rackspace.com/ubuntu/ precise-updates universe deb-src http://mirror.rackspace.com/ubuntu/ precise-updates universe
Agora o “pulo do gato”, fazer com que os pacotes do PHP e do Apache utilizem este repositório
/etc/apt/preferences.d/php_precise
Package: php5 Pin: release a=precise Pin-Priority: 1001 Package: php* Pin: release a=precise Pin-Priority: 1001 Package: php-* Pin: release a=precise Pin-Priority: 1001 Package: libapache2-mod-php5 Pin: release a=precise Pin-Priority: 1001 Package: php5 Pin: release a=precise-updates Pin-Priority: 1001 Package: php* Pin: release a=precise-updates Pin-Priority: 1001 Package: php-* Pin: release a=precise-updates Pin-Priority: 1001 Package: libapache2-mod-php5 Pin: release a=precise-updates Pin-Priority: 1001 Package: apache2-* Pin: release a=precise Pin-Priority: 1001 Package: apache2-* Pin: release a=precise-updates Pin-Priority: 1002 Package: apache2* Pin: release a=precise Pin-Priority: 1001 Package: apache2* Pin: release a=precise-updates Pin-Priority: 1002
OBS: Os pacotes do apache são necessários caso você vá utilizar mod_php, se for utilizar php-fpm ou php-cgi, basta retirar os grupos referentes ao apache no arquivo acima.
Agora basta instalar os software e “voilà”
apt-get update apt-get install apache2 php5 libapache2-mod-php5
Todo esses procedimentos que citei (compilação, procura de ppa, testes), levaram horas do meu tempo livre, então se você estiver lendo isso e lhe for útil, um belo agradecimento seria um compartilhamento no facebook! 😉
Certificado SSL gratuito
Pra quem quer contratar um certificado SSL e não quer gastar grana.
https://www.startssl.com/
OBS: O certificado gratuito (level1) não permite o uso em sites de ecommerce, para este tipo de site eles possuem o level2 que é US$ 59,90 a cada dois anos, porém o certificado é emitido para *.dominio (wildcard) que é um preço que ta valendo a pena. =)
Desabilitar mod_gzip para URL específica
Sintaxe de uso:
SetEnvIf Request_URI [regex] no-gzip dont-vary
Exemplo (retirando mod_gzip da index.php):
SetEnvIf Request_URI index\.php no-gzip dont-vary
Tela em branco ao incluir arquivos .phar no php-fpm
Ao tentar utilizar recurso de arquivos .phar em um servidor rodando php-fpm retornava tela em branco.
Isso acontecia porque o suhosin estava bloqueando o include de arquivo .phar, sendo necessário a inclusão da linha abaixo no php.ini
suhosin.executor.include.whitelist ="phar"
Nota: Estou usando php-fpm, mas como o erro estava no módulo suhosin, deve funcionar também com fastcgi ou mod_php
Compilando ffmpeg-php nas ultimas versões do ffmpeg
A última versão do ffmpeg-php disponibilizada no sourceforge foi liberada em meados de 2008 e desde então não teve mais atualização, isso ocasiona erro ao compilar usando versões mais novas do ffmpeg, pois houveram mudanças nas chamadas de api do ffmpeg. (pelo menos foi a explicação que achei em alguns forums)
Eles tem uma versão “nigthly” que é trablahada diretamente no SVN, parece ter desenvolvimento ativo, visto que tem commits de “apenas” 2 meses atrás, o que não entendo é porque não lançam releases em cima desse svn…
Bem, de toda forma, a versão do svn compila perfeitamente nas versões mais novas do ffmpeg, processo de instalação abaixo:
cd /tmp/install wget "http://ffmpeg-php.svn.sourceforge.net/viewvc/ffmpeg-php/trunk/ffmpeg-php/?view=tar" -O ffmpegphp-novo.tar.gz tar xzvf ffmpegphp-novo.tar.gz cd ffmpeg-php/ phpize ./configure make && make install ln -s /usr/local/lib/php/extensions/no-debug-non-zts-20060613/ffmpeg.so /usr/local/lib/ffmpeg.so
Adicionar no php.ini:
Extension=ffmpeg.so
Procedimentos adicionais:
– Reiniciar apache
– Se estiver rodando qualquer tipo de php-cgi (apache, ngxin, lighttpd, etc) matar o php-cgi (incluindo o processo pai) e subir novamente os processos
Compiling mod_rpaf on Apache 2.4
Another module with error in make command and more patches to do…
[13:02:59 root@template-centos-6-2 mod_rpaf-0.6]# /usr/local/apache2/bin/apxs -i -c -n mod_rpaf-2.0.so mod_rpaf-2.0.c /usr/local/apache2/build/libtool --silent --mode=compile gcc -std=gnu99 -prefer-pic -D_REENTRANT -D_GNU_SOURCE -g -O2 -pthread -I/usr/local/apache2/include -I/usr/local/apache2/include -I/usr/local/apache2/include -c -o mod_rpaf-2.0.lo mod_rpaf-2.0.c && touch mod_rpaf-2.0.slo mod_rpaf-2.0.c: In function 'rpaf_cleanup': mod_rpaf-2.0.c:150: error: 'conn_rec' has no member named 'remote_ip' mod_rpaf-2.0.c:151: error: 'conn_rec' has no member named 'remote_addr' mod_rpaf-2.0.c:151: warning: implicit declaration of function 'inet_addr' mod_rpaf-2.0.c:151: error: 'conn_rec' has no member named 'remote_ip' mod_rpaf-2.0.c: In function 'change_remote_ip': mod_rpaf-2.0.c:164: error: 'conn_rec' has no member named 'remote_ip' mod_rpaf-2.0.c:183: error: 'conn_rec' has no member named 'remote_ip' mod_rpaf-2.0.c:186: error: 'conn_rec' has no member named 'remote_ip' mod_rpaf-2.0.c:187: error: 'conn_rec' has no member named 'remote_addr' mod_rpaf-2.0.c:187: error: 'conn_rec' has no member named 'remote_ip' apxs:Error: Command failed with rc=65536
Below, the full source of patched mod_rpaf-2.0.c that works on apache 2.4
/* ==================================================================== * Copyright (c) 1995 The Apache Group. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the Apache Group * for use in the Apache HTTP server project (http://www.apache.org/)." * * 4. The names "Apache Server" and "Apache Group" must not be used to * endorse or promote products derived from this software without * prior written permission. * * 5. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the Apache Group * for use in the Apache HTTP server project (http://www.apache.org/)." * * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Group and was originally based * on public domain software written at the National Center for * Supercomputing Applications, University of Illinois, Urbana-Champaign. * For more information on the Apache Group and the Apache HTTP server * project, please see <http://www.apache.org/>. * */ /* * $Id: mod_rpaf-2.0.c 18 2008-01-01 03:05:40Z thomas $ * * Author: Thomas Eibner, <[email protected]> * URL: http://stderr.net/apache/rpaf/ * rpaf is short for reverse proxy add forward * * This module does the opposite of mod_proxy_add_forward written by * Ask Bjørn Hansen. http://develooper.com/code/mpaf/ or mod_proxy * in 1.3.25 and above and mod_proxy from Apache 2.0 * */ #include "httpd.h" #include "http_config.h" #include "http_core.h" #include "http_log.h" #include "http_protocol.h" #include "http_vhost.h" #include "apr_strings.h" module AP_MODULE_DECLARE_DATA rpaf_module; typedef struct { int enable; int sethostname; const char *headername; apr_array_header_t *proxy_ips; } rpaf_server_cfg; typedef struct { const char *old_ip; request_rec *r; } rpaf_cleanup_rec; static void *rpaf_create_server_cfg(apr_pool_t *p, server_rec *s) { rpaf_server_cfg *cfg = (rpaf_server_cfg *)apr_pcalloc(p, sizeof(rpaf_server_cfg)); if (!cfg) return NULL; cfg->proxy_ips = apr_array_make(p, 0, sizeof(char *)); cfg->enable = 0; cfg->sethostname = 0; return (void *)cfg; } static const char *rpaf_set_proxy_ip(cmd_parms *cmd, void *dummy, const char *proxy_ip) { server_rec *s = cmd->server; rpaf_server_cfg *cfg = (rpaf_server_cfg *)ap_get_module_config(s->module_config, &rpaf_module); /* check for valid syntax of ip */ *(char **)apr_array_push(cfg->proxy_ips) = apr_pstrdup(cmd->pool, proxy_ip); return NULL; } static const char *rpaf_set_headername(cmd_parms *cmd, void *dummy, const char *headername) { server_rec *s = cmd->server; rpaf_server_cfg *cfg = (rpaf_server_cfg *)ap_get_module_config(s->module_config, &rpaf_module); cfg->headername = headername; return NULL; } static const char *rpaf_enable(cmd_parms *cmd, void *dummy, int flag) { server_rec *s = cmd->server; rpaf_server_cfg *cfg = (rpaf_server_cfg *)ap_get_module_config(s->module_config, &rpaf_module); cfg->enable = flag; return NULL; } static const char *rpaf_sethostname(cmd_parms *cmd, void *dummy, int flag) { server_rec *s = cmd->server; rpaf_server_cfg *cfg = (rpaf_server_cfg *)ap_get_module_config(s->module_config, &rpaf_module); cfg->sethostname = flag; return NULL; } static int is_in_array(const char *remote_ip, apr_array_header_t *proxy_ips) { int i; char **list = (char**)proxy_ips->elts; for (i = 0; i < proxy_ips->nelts; i++) { if (strcmp(remote_ip, list[i]) == 0) return 1; } return 0; } static apr_status_t rpaf_cleanup(void *data) { rpaf_cleanup_rec *rcr = (rpaf_cleanup_rec *)data; rcr->r->connection->client_ip = apr_pstrdup(rcr->r->connection->pool, rcr->old_ip); rcr->r->connection->client_addr->sa.sin.sin_addr.s_addr = apr_inet_addr(rcr->r->connection->client_ip); return APR_SUCCESS; } static int change_remote_ip(request_rec *r) { const char *fwdvalue; char *val; rpaf_server_cfg *cfg = (rpaf_server_cfg *)ap_get_module_config(r->server->module_config, &rpaf_module); if (!cfg->enable) return DECLINED; if (is_in_array(r->connection->client_ip, cfg->proxy_ips) == 1) { /* check if cfg->headername is set and if it is use that instead of X-Forwarded-For by default */ if (cfg->headername && (fwdvalue = apr_table_get(r->headers_in, cfg->headername))) { // } else if (fwdvalue = apr_table_get(r->headers_in, "X-Forwarded-For")) { // } else { return DECLINED; } if (fwdvalue) { rpaf_cleanup_rec *rcr = (rpaf_cleanup_rec *)apr_pcalloc(r->pool, sizeof(rpaf_cleanup_rec)); apr_array_header_t *arr = apr_array_make(r->pool, 0, sizeof(char*)); while (*fwdvalue && (val = ap_get_token(r->pool, &fwdvalue, 1))) { *(char **)apr_array_push(arr) = apr_pstrdup(r->pool, val); if (*fwdvalue != ' ') ++fwdvalue; } rcr->old_ip = apr_pstrdup(r->connection->pool, r->connection->client_ip); rcr->r = r; apr_pool_cleanup_register(r->pool, (void *)rcr, rpaf_cleanup, apr_pool_cleanup_null); r->connection->client_ip = apr_pstrdup(r->connection->pool, ((char **)arr->elts)[((arr->nelts)-1)]); r->connection->client_addr->sa.sin.sin_addr.s_addr = apr_inet_addr(r->connection->client_ip); if (cfg->sethostname) { const char *hostvalue; if (hostvalue = apr_table_get(r->headers_in, "X-Forwarded-Host")) { /* 2.0 proxy frontend or 1.3 => 1.3.25 proxy frontend */ apr_table_set(r->headers_in, "Host", apr_pstrdup(r->pool, hostvalue)); r->hostname = apr_pstrdup(r->pool, hostvalue); ap_update_vhost_from_headers(r); } else if (hostvalue = apr_table_get(r->headers_in, "X-Host")) { /* 1.3 proxy frontend with mod_proxy_add_forward */ apr_table_set(r->headers_in, "Host", apr_pstrdup(r->pool, hostvalue)); r->hostname = apr_pstrdup(r->pool, hostvalue); ap_update_vhost_from_headers(r); } } } } return DECLINED; } static const command_rec rpaf_cmds[] = { AP_INIT_FLAG( "RPAFenable", rpaf_enable, NULL, RSRC_CONF, "Enable mod_rpaf" ), AP_INIT_FLAG( "RPAFsethostname", rpaf_sethostname, NULL, RSRC_CONF, "Let mod_rpaf set the hostname from X-Host header and update vhosts" ), AP_INIT_ITERATE( "RPAFproxy_ips", rpaf_set_proxy_ip, NULL, RSRC_CONF, "IP(s) of Proxy server setting X-Forwarded-For header" ), AP_INIT_TAKE1( "RPAFheader", rpaf_set_headername, NULL, RSRC_CONF, "Which header to look for when trying to find the real ip of the client in a proxy setup" ), { NULL } }; static void register_hooks(apr_pool_t *p) { ap_hook_post_read_request(change_remote_ip, NULL, NULL, APR_HOOK_FIRST); } module AP_MODULE_DECLARE_DATA rpaf_module = { STANDARD20_MODULE_STUFF, NULL, NULL, rpaf_create_server_cfg, NULL, rpaf_cmds, register_hooks, };
Hope it helps ^^
Compiling mod_jk on apache 2.4
Sorry for brazilian users that cant read it, but at this time, i will post in english, because this can help everyone to solve this problem.
Im was trying to compile mod_jk on the lastest version of apache (2.4) and get this error on “make”
Making all in apache-2.0
make[1]: Entering directory `/usr/local/install/Java-packages/tomcat-connectors-1.2.32-src/native/apache-2.0′
/usr/local/apache2/build/libtool –silent –mode=compile gcc -std=gnu99 -I/usr/local/apache2/include -DHAVE_CONFIG_H -DUSE_APACHE_MD5 -I ../common -I /usr/java/j2sdk//include -I /usr/java/j2sdk//include/unix -D_REENTRANT -D_GNU_SOURCE -g -O2 -pthread -DHAVE_APR -I/usr/local/apache2/include -I/usr/local/apache2/include -DHAVE_CONFIG_H -g -O2 -pthread -D_REENTRANT -D_GNU_SOURCE -c mod_jk.c -o mod_jk.lo
mod_jk.c: In function ‘init_ws_service’:
mod_jk.c:767: error: ‘conn_rec’ has no member named ‘remote_ip’
mod_jk.c:768: error: ‘conn_rec’ has no member named ‘remote_addr’
mod_jk.c:1036: error: ‘conn_rec’ has no member named ‘remote_ip’
mod_jk.c:1036: error: ‘conn_rec’ has no member named ‘remote_ip’
make[1]: *** [mod_jk.lo] Error 1
Reading the API documentation i found the solution.
the file apache-2.0/mod_jk.c uses conn_rec->remote_ip and conn_rec->remote_addr that was discontinued on the new API
For a perfect compilation, edit apache-2.0/mod_jk.c file and change the lines below:
Line 767:
Before:
s->remote_addr = r->connection->remote_ip;
After (with patch):
s->remote_addr = r->connection->client_ip;
Line 768:
Before:
s->remote_port = apr_itoa(r->pool, r->connection->remote_addr->port);
After:
s->remote_port = apr_itoa(r->pool, r->connection->client_addr->port);
Line 1036:
Before:
STRNULL_FOR_NULL(r->connection->remote_ip),
After:
STRNULL_FOR_NULL(r->connection->client_ip),
Now, the “make” command can run perfect! 😉
Obtendo IP real em uma aplicação web atrás de um proxy reverso
Quando utilizamos um proxy reverso como varnish ou nginx (até mesmo com o apache da pra fazer isso) temos um pequeno problema em aplicações que logam ip do usuário (como um sistema de comentários, por exemplo).
Ao configurar um proxy reverso, normalmente denominamos um header separado para o IP real da aplicação, pode ser qualquer header, mas normalmente é utilizado o header X–Forwarded–For (que chamamos de XFF)
Existem diversas soluções para isto, a primeira atraves de php, bastando inserir o código abaixo em algum arquivo de include global (como arquivo de conexão ao banco)
<?php $_SERVER['REMOTE_ADDR'] = $_SERVER['X_FORWARDED_FOR']; ?>
Para uma solução a nível de webserver (apache) podemos usar o mod_rpaf.
Para instalar no ubuntu (e distros baseadas em debian)
apt-get install libapache2-mod-rpaf
Para demais distros, pode-se obter o source na página do projeto:
http://stderr.net/apache/rpaf/