PHP do Básico ao Avançado – Aula 13 – PHP na linha de comando (SHELL) e Autenticação por Sessões
Nesta aula, vamos falar sobre funções pouco conhecidas ou pouco usadas do PHP para a criação de scripts de teste (PENTEST) ou de manipulação de dados e conexões diretamente pela linha de comando. E falaremos também, como podemos fazer um sistema de LOGIN/AUTENTICAÇÃO básicos, usando recursos presentes nativamente no próprio protocolo HTTP ou FTP e integrando ele com seus scripts da web.
Uso pela LINHA DE COMANDO (SHELL)
Executar um script pela linha de comando, é extremamente útil, para automatiza tarefas m um servidor, para usar a facilidade do PHP em usar protocolos como FTP ou HTTP/HTTPS para fazer um deploy ou uma cópia de segurança, ou mesmo para fazer verificações de portas abertas em um determinado host (PENTEST) ou qualquer outra função de análise de dados.
Você consegue, usar leitura de dados do usuário, como em:
$handle = fopen ("php://stdin","r"); $line = fgets($handle);
Ou mesmo receber dados através de parâmetros:
parse_str(implode('&', array_slice($argv, 1)), $_ARGS);
Que cria um array $_ARGS[‘var’]=value que pode ser usado da mesma maneira que os arrays mágicos $_GET ou $_POST. Ou mesmo criar executáveis tipo SCRIPT SHELL usando o shebang em sistemas POSIX como linux ou MacOS como em:
#!/usr/bin/php <?php phpinfo(); ?>
Dar um chmod 755 vai permitir que seu dono o execute como um programa do terminal. Já pensou como isso é extremamente útil, por exemplo para fazer a cópia ou envio de arquivos, ou para fazer tarefas agendadas na CRON que possam incluir rotinas por exemplo em seu banco de dados?
Você pode verificar a versão do PHP, e outros detalhes executando php -v diretamente na linha de comando, ou especificar o diretório em caso do binário ou executável não estar na variável PATH do ambiente. A saída do comando é similar a:
/$ php -v PHP 7.4.3 (cli) (built: Oct 6 2020 15:47:56) ( NTS ) Copyright (c) The PHP Group Zend Engine v3.4.0, Copyright (c) Zend Technologies with Zend OPcache v7.4.3, Copyright (c), by Zend Technologies
Quando executamos o PHP no modo CLI da linha de comando, as mensagens de erro passam a ser enviadas em modo texto, no lugar do modo html normal do GCI e de outros modos. Existem certas diretivas do php.ini que são sobrescritas pelas do CLI SAPI porque elas não fazem sentido em um ambiente de linha de comando.
NOTA TÉCNICA: Assim como qualquer aplicação de linha de comando, o PHP aceita qualquer quantidade argumentos; entretanto, os scripts PHP também podem receber outros argumentos. A quantidade de argumentos que podem ser passados para o script não é limitada pelo PHP (e apesar do shell ter um limite no número de caracteres que podem ser passados, ele não é geralmente atingido).
A partir do PHP 5.4, os argumentos passados para o scripts ficam disponíveis no array global $argv. O primeiro índice (zero) sempre contém o nome do script que está sendo chamado pela linha de comando. Note que, se o código é executado diretamente usando a opção de linha de comando -r, o valor de $argv[0] será somente um hífen (-). O mesmo é verdadeiro se o código e redirecionado pelo STDIN.
O executável do PHP pode ser usado para rodar scripts absolutamente independetes do servidor web. Em sistemas Unix, a primeira linha especial #! (ou “shebang”) deve ser adicionada a sripts PHP para que o sistema possa automaticamente dizer qual programa deve executar o script. Em plataformas Windows, é possível associar o php.exe com um clique duplo no arquivos com extensão .php, ou um arquivo batch pode ser criado para rodar scripts através do PHP. A primeira linha especial shebang para Unix não causa nenhum efeito no Windows (Já que é formatada como um comentário PHP), então programas multiplataforma podem ser escritos com a inclusão disso. Um exemplo simples de programa de linha de comando em PHP é mostrado abaixo:
#!/usr/bin/php <?php if ($argc != 2 || in_array($argv[1], array('--help', '-help', '-h', '-?'))) { ?> AJUDA INTERATIVA USO: <?php echo $argv[0]; ?> <option> <option> pode ser alguma palavra que você gostaria para imprimir. ou Com o --help, -help, -h, ou -? opções, você pode obter essa ajuda. <?php } else { echo $argv[1]; } ?>
O modo CLI, define algumas constantes, que permitem facilitar a leitura de entradas através de arquivos executados a partir da linha de comando, como:
<?php $line = trim(fgets(STDIN)); // Faz a leitura de uma linha de etxto fscanf(STDIN, "%d\n", $number); // faz a leitura de um formato numérico ?>
Vamos escrever um script SHELL um pouco mais útil:
#!/usr/bin/php <?php $host = '127.0.0.1'; for($i=1;$i<65535; $i++) { $connection = @fsockopen($host, $i); if (is_resource($connection)) { echo $host . ':' . $i . ' ' . '(' . getservbyport($i, 'tcp') . ') is open.</h2>' . "\n"; fclose($connection); } }
A saída deste script é basicamente:
127.0.0.1:21 (ftp) is open.</h2> 127.0.0.1:22 (ssh) is open.</h2> 127.0.0.1:25 (smtp) is open.</h2> 127.0.0.1:80 (http) is open.</h2> 127.0.0.1:139 (netbios-ssn) is open.</h2> 127.0.0.1:443 (https) is open.</h2> 127.0.0.1:445 (microsoft-ds) is open.</h2> 127.0.0.1:631 (ipp) is open.</h2> 127.0.0.1:1234 () is open.</h2> 127.0.0.1:1716 () is open.</h2> 127.0.0.1:5939 () is open.</h2> 127.0.0.1:8080 (http-alt) is open.</h2> 127.0.0.1:27017 () is open.</h2> 127.0.0.1:39178 () is open.</h2> 127.0.0.1:54914 () is open.</h2>
E mostra todas as portas abertas em localhost. Em outras oportunidades, vamos escrever mais códigos que usem a funcionalidade da linha de comando do PHP.
Autenticação por Sessões
Todo o controle de acesso é feito de maneira semi automatizada e é baseado em SSSÕES, e o gerenciamento de sessões HTTP é o núcleo de segurança na web, e consequentemente, em PHP portanto toda prevenção deve ser adotada para garantir a segurança.
O módulo de sessão não garante que a informação armazenada em uma sessão seja visualizada apenas pelo usuário que criou a sessão, por este motivo, devemos tomar o máximo de cuidado para ter a garantia de que o acesso possui todo o controle. Por exemplo, para proteger os usuários de táticas de engenharia social simples, deve ser habilitada a opção session.use_only_cookies. E nesse caso, os cookies devem obrigatoriamente estar habilitados no lado do usuário, ou as sessões não irão funcionar.
Caso não estejam criptografados, os IDs de sessão serão transmitidos em texto puro/simples pela rede, e podem ser facilmente interceptados por um sniffer ou ficarem salvos nos logs de cesso de provedores e redes intermediarias e até mesmo nos VPNs. Nesse caso a solução é implementar SSL/TLS em seu servidor e torná-lo obrigatório para os usuários.
São boas práticas de programação com PHP garantir que as sessões tenham um tempo de validade, e um tempo de inatividade, bem como manter os dados de login o mais seguro possível, com uso adequado de autenticação em cada módulo, não permitir acesso a módulos fora do curso normal, ou acesso direto a diretórios do servidor web, que possam ser gravados ou alterados publicamente.
Uma das implementações mais simples é prefixar o ID de sessão com o ID do usuário e armazenar as informações necessárias na $_SESSION. Muitos bancos de dados tem boa performance para selecionar o prefixo de uma string. Você pode usar session_regenerate_id() e session_create_id() para isso. O gerenciamento de sessão baseada em timestamp é necessário para detectar acesso em sessões obsoletas.
Um ponto importante, é a maioria dos COOKIES que tem como objetivo salvar os dados de sessão, devem ser expirados automaticamente, após o fechamento do navegador, seu PHP.INI ou outro arquivo de configuração deve ter a diretiva session.cookie_lifetime=0
pois isso garante que o cookie da sessão seja salvo somente em memória. O uso dessa diretiva em conjunto com session.use_cookies=On
é uma forma de aumentar a segurança. Se adicionar a camada de que somente pelos cookies é que as sessões podem ser validadas usando session.use_only_cookies=On
temos que embora o cookie HTTP ainda tenha alguns problemas, ele é o modo preferido para gerenciar o ID de sessão. Com session.use_strict_mode=On
outra camada de proteção de IDs inválidos é adicionada e session.cookie_httponly=On
que proíbe o acesso ao cookie de sessão através do JavaScript e evita o roubo de cookies por injeção de JavaScript.
Quando o site possui HTTPS habilitado, o que é uma necessidade em termos de segurança e melhores práticas, a diretiva session.cookie_secure=On
exige que o uso do SSL seja ativado para o inicio de uma sessão. Além claro do uso de session.use_trans_sid=Off
que oculta o ID de dentro das páginas geradas, evitando que ela possa estar presente por exemplo em um link enviado. session.cache_limiter=nocache
evita que cookies e IDs de sessão sejam salvos em cache.
session.gc_maxlifetime
é a configuração para remoção de ID de sessão obsoleta, diretamente pelo PHP por isso depender dessa configuração NÃO é recomendado, e ela tem melhores vantagens se sua aplicação tiver um script que rode diretamente na CRON do servidor, onde seja entre outras tarefas agendadas a coleta de lixo (garbage collection) da sessão seja feita pela função session_gc() que roda de maneira periódica, conforme as necessidades de sua aplicação.
session.sid_length="48"
é hoje o tamanho ideal, de uma string de ID de sessão, já que os 16 do padrão do PHP podem ser facilmente quebrados, além de que session.hash_function="sha256"
é um dos algoritmos mais seguros em relação a outros e é o padrão em versões mais novas como o 7.0 ou superior.
Outros Detalhes
Por padrão, todos os dados relacionados com uma sessão em particular serão armazenados em um arquivo no diretório especificado pela configuração INI session.save_path
em um arquivo para cada sessão, e é independente se alguma informação está associada com esta sessão ou não, ele será criado. Isto é devido ao fato de que uma sessão é aberta. Note que este comportamento é um efeito colateral das limitações de trabalhar com o sistema de arquivo e é possível que um manipulador de sessão personalizado (como um que utilize banco de dados) não mantenha registros das sessões que não contém dados.
Lembre-se que este diretório não pode estar dentro da árvore de diretórios acessadas via HTTP e mesmo em HTTPS pois estes arquivos contém os dados brutos de todo o conteúdo salvo nas variáveis de sessão, e só são eliminados pelo Garbage Collector. Uma boa prática em sistemas POSIX é armazenar esses arquivos em /tmp que é esvaziado toda a vez que o servidor precisar ser reiniciado, ou em um subdiretório de /tmp que você possa esvaziar periodicamente ou conforme a data e hora de criação dos arquivos ou de alguma maneira que desejar diretamente através da CRON do servidor.
Já para servidores compartilhados, o uso de /tmp pode ser uma falha, pois pode permitir que outros usuários raptem uma sessão ativa, nestes casos o uso de um subdiretório no seu diretório ~HOME pode ser uma solução.
Conclusão
Bem agora que você já conhece todos os recursos da linguagem padrão e suas particularidades, vamos dar inicio a uma explicação de cada uma das funções que por padrão vem junto com o PHP pois são elas que vão permitir ao programador o uso eficiente dos recursos e uma correta manipulação dos dados afim de produzir o resultado esperado.
Optamos por separar cada grupo de funções similares ou correlatas em uma aula específica, servindo como um guia, com exemplos de uso e funcionalidades no dia a dia real.