Boas Práticas de Segurança
2.5.x ✅ 4.0.x ✅
Este documento fornece boas práticas de segurança abrangentes para desenvolvedores de módulos XOOPS. Seguindo essas diretrizes, você ajudará a garantir que seus módulos sejam seguros e não introduzam vulnerabilidades em instalações XOOPS.
Princípios de Segurança
Seção intitulada “Princípios de Segurança”Todo desenvolvedor XOOPS deve seguir estes princípios fundamentais de segurança:
- Defesa em Profundidade: Implementar múltiplas camadas de controles de segurança
- Privilégio Mínimo: Fornecer apenas os direitos de acesso mínimos necessários
- Validação de Entrada: Nunca confiar em entrada do usuário
- Seguro por Padrão: A segurança deve ser a configuração padrão
- Mantenha Simples: Sistemas complexos são mais difíceis de proteger
Documentação Relacionada
Seção intitulada “Documentação Relacionada”- CSRF-Protection - Sistema de token e classe XoopsSecurity
- Input-Sanitization - MyTextSanitizer e validação
- SQL-Injection-Prevention - Práticas de segurança de banco de dados
Lista de Verificação Rápida
Seção intitulada “Lista de Verificação Rápida”Antes de liberar seu módulo, verifique:
- Todos os formulários incluem tokens XOOPS
- Toda entrada do usuário é validada e sanitizada
- Toda saída é adequadamente escapada
- Todas as consultas de banco de dados usam prepared statements
- Uploads de arquivo são devidamente validados
- Verificações de autenticação e autorização estão em vigor
- Tratamento de erro não revela informações sensíveis
- Configuração sensível está protegida
- Bibliotecas de terceiros estão atualizadas
- Testes de segurança foram realizados
Autenticação e Autorização
Seção intitulada “Autenticação e Autorização”Verificando Autenticação de Usuário
Seção intitulada “Verificando Autenticação de Usuário”// Verificar se o usuário está conectadoif (!is_object($GLOBALS['xoopsUser'])) { redirect_header(XOOPS_URL, 3, _NOPERM); exit();}Verificando Permissões de Usuário
Seção intitulada “Verificando Permissões de Usuário”// Verificar se o usuário tem permissão para acessar este móduloif (!$GLOBALS['xoopsUser']->isAdmin($xoopsModule->mid())) { redirect_header(XOOPS_URL, 3, _NOPERM); exit();}
// Verificar permissão específica$moduleHandler = xoops_getHandler('module');$module = $moduleHandler->getByDirname('mymodule');$moduleperm_handler = xoops_getHandler('groupperm');$groups = $GLOBALS['xoopsUser']->getGroups();
if (!$moduleperm_handler->checkRight('mymodule_view', $item_id, $groups, $module->getVar('mid'))) { redirect_header(XOOPS_URL, 3, _NOPERM); exit();}Configurando Permissões de Módulo
Seção intitulada “Configurando Permissões de Módulo”// Criar permissão na função de instalação/atualização$gpermHandler = xoops_getHandler('groupperm');$gpermHandler->deleteByModule($module->getVar('mid'), 'mymodule_view');
// Adicionar permissão para todos os grupos$groups = [XOOPS_GROUP_ADMIN, XOOPS_GROUP_USERS, XOOPS_GROUP_ANONYMOUS];foreach ($groups as $group_id) { $gpermHandler->addRight('mymodule_view', 1, $group_id, $module->getVar('mid'));}Segurança de Sessão
Seção intitulada “Segurança de Sessão”Boas Práticas de Manipulação de Sessão
Seção intitulada “Boas Práticas de Manipulação de Sessão”- Não armazenar informações sensíveis na sessão
- Regenerar IDs de sessão após login/mudanças de privilégio
- Validar dados da sessão antes de usá-los
// Regenerar ID de sessão após loginsession_regenerate_id(true);
// Validar dados da sessãoif (isset($_SESSION['mymodule_user_id'])) { $user_id = (int)$_SESSION['mymodule_user_id']; // Verificar se o usuário existe no banco de dados}Prevenindo Fixação de Sessão
Seção intitulada “Prevenindo Fixação de Sessão”// Após login bem-sucedidosession_regenerate_id(true);$_SESSION['mymodule_user_ip'] = $_SERVER['REMOTE_ADDR'];
// Em requisições subsequentesif ($_SESSION['mymodule_user_ip'] !== $_SERVER['REMOTE_ADDR']) { // Possível tentativa de sequestro de sessão session_destroy(); redirect_header('index.php', 3, 'Erro de sessão'); exit();}Segurança de Upload de Arquivo
Seção intitulada “Segurança de Upload de Arquivo”Validando Uploads de Arquivo
Seção intitulada “Validando Uploads de Arquivo”// Verificar se o arquivo foi carregado corretamenteif (!isset($_FILES['userfile']) || $_FILES['userfile']['error'] != UPLOAD_ERR_OK) { redirect_header('index.php', 3, 'Erro no upload de arquivo'); exit();}
// Verificar tamanho de arquivoif ($_FILES['userfile']['size'] > 1000000) { // limite de 1MB redirect_header('index.php', 3, 'Arquivo muito grande'); exit();}
// Verificar tipo de arquivo$allowed_types = ['image/jpeg', 'image/png', 'image/gif'];if (!in_array($_FILES['userfile']['type'], $allowed_types)) { redirect_header('index.php', 3, 'Tipo de arquivo inválido'); exit();}
// Validar extensão de arquivo$filename = $_FILES['userfile']['name'];$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));$allowed_extensions = ['jpg', 'jpeg', 'png', 'gif'];if (!in_array($ext, $allowed_extensions)) { redirect_header('index.php', 3, 'Extensão de arquivo inválida'); exit();}Usando XOOPS Uploader
Seção intitulada “Usando XOOPS Uploader”include_once XOOPS_ROOT_PATH . '/class/uploader.php';
$allowed_mimetypes = ['image/gif', 'image/jpeg', 'image/png'];$maxsize = 1000000; // 1MB$maxwidth = 1024;$maxheight = 768;$upload_dir = XOOPS_ROOT_PATH . '/uploads/mymodule';
$uploader = new XoopsMediaUploader( $upload_dir, $allowed_mimetypes, $maxsize, $maxwidth, $maxheight);
if ($uploader->fetchMedia('userfile')) { $uploader->setPrefix('mymodule_');
if ($uploader->upload()) { $filename = $uploader->getSavedFileName(); // Salvar nome do arquivo no banco de dados } else { echo $uploader->getErrors(); }} else { echo $uploader->getErrors();}Armazenando Arquivos Carregados com Segurança
Seção intitulada “Armazenando Arquivos Carregados com Segurança”// Definir diretório de upload fora da raiz web$upload_dir = XOOPS_VAR_PATH . '/uploads/mymodule';
// Criar diretório se não existirif (!is_dir($upload_dir)) { mkdir($upload_dir, 0755, true);}
// Mover arquivo carregadomove_uploaded_file($_FILES['userfile']['tmp_name'], $upload_dir . '/' . $safe_filename);Tratamento de Erro e Logging
Seção intitulada “Tratamento de Erro e Logging”Tratamento Seguro de Erro
Seção intitulada “Tratamento Seguro de Erro”try { $result = someFunction(); if (!$result) { throw new Exception('Operação falhou'); }} catch (Exception $e) { // Registrar o erro xoops_error($e->getMessage());
// Exibir uma mensagem de erro genérica para o usuário redirect_header('index.php', 3, 'Ocorreu um erro. Tente novamente mais tarde.'); exit();}Logging de Eventos de Segurança
Seção intitulada “Logging de Eventos de Segurança”// Registrar eventos de segurançaxoops_loadLanguage('logger', 'mymodule');$GLOBALS['xoopsLogger']->addExtra('Segurança', 'Tentativa de login falhada para usuário: ' . $username);Segurança de Configuração
Seção intitulada “Segurança de Configuração”Armazenando Configuração Sensível
Seção intitulada “Armazenando Configuração Sensível”// Definir caminho de configuração fora da raiz web$config_path = XOOPS_VAR_PATH . '/configs/mymodule/config.php';
// Carregar configuraçãoif (file_exists($config_path)) { include $config_path;} else { // Lidar com configuração ausente}Protegendo Arquivos de Configuração
Seção intitulada “Protegendo Arquivos de Configuração”Use .htaccess para proteger arquivos de configuração:
# Em .htaccess<Files "config.php"> Order Allow,Deny Deny from all</Files>Bibliotecas de Terceiros
Seção intitulada “Bibliotecas de Terceiros”Selecionando Bibliotecas
Seção intitulada “Selecionando Bibliotecas”- Escolher bibliotecas mantidas ativamente
- Verificar vulnerabilidades de segurança
- Verificar se a licença da biblioteca é compatível com XOOPS
Atualizando Bibliotecas
Seção intitulada “Atualizando Bibliotecas”// Verificar versão da bibliotecaif (version_compare(LIBRARY_VERSION, '1.2.3', '<')) { xoops_error('Por favor, atualize a biblioteca para a versão 1.2.3 ou superior');}Isolando Bibliotecas
Seção intitulada “Isolando Bibliotecas”// Carregar biblioteca de forma controladafunction loadLibrary($file){ $allowed = ['parser.php', 'formatter.php'];
if (!in_array($file, $allowed)) { return false; }
include_once XOOPS_ROOT_PATH . '/modules/mymodule/libraries/' . $file; return true;}Testes de Segurança
Seção intitulada “Testes de Segurança”Lista de Verificação de Testes Manuais
Seção intitulada “Lista de Verificação de Testes Manuais”- Testar todos os formulários com entrada inválida
- Tentar contornar autenticação e autorização
- Testar funcionalidade de upload de arquivo com arquivos maliciosos
- Verificar vulnerabilidades XSS em toda saída
- Testar injeção de SQL em todas as consultas de banco de dados
Testes Automatizados
Seção intitulada “Testes Automatizados”Use ferramentas automatizadas para verificar vulnerabilidades:
- Ferramentas de análise de código estática
- Scanners de aplicação web
- Verificadores de dependência para bibliotecas de terceiros
Escapando Saída
Seção intitulada “Escapando Saída”Contexto HTML
Seção intitulada “Contexto HTML”// Para conteúdo HTML regularecho htmlspecialchars($variable, ENT_QUOTES, 'UTF-8');
// Usando MyTextSanitizer$myts = MyTextSanitizer::getInstance();echo $myts->htmlSpecialChars($variable);Contexto JavaScript
Seção intitulada “Contexto JavaScript”// Para dados usados em JavaScriptecho json_encode($variable);
// Para JavaScript inlineecho 'var data = ' . json_encode($variable) . ';';Contexto URL
Seção intitulada “Contexto URL”// Para dados usados em URLsecho htmlspecialchars(urlencode($variable), ENT_QUOTES, 'UTF-8');Variáveis de Template
Seção intitulada “Variáveis de Template”// Atribuir variáveis ao template Smarty$GLOBALS['xoopsTpl']->assign('title', htmlspecialchars($title, ENT_QUOTES, 'UTF-8'));
// Para conteúdo HTML que deve ser exibido como está$GLOBALS['xoopsTpl']->assign('content', $myts->displayTarea($content, 1, 1, 1, 1, 1));Recursos
Seção intitulada “Recursos”#segurança #boas-práticas #xoops #desenvolvimento-módulo #autenticação #autorização