--- name: perfex-security description: Perfex CRM module security. Input validation, CSRF, XSS prevention, directory traversal. Based on official documentation only. Use when user mentions "perfex security", "input validation", "csrf perfex", "xss protection". author: Descomplicar® Crescimento Digital version: 1.0.0 quality_score: 70 user_invocable: true desk_task: null --- # /perfex-security - Segurança Módulos Perfex CRM Práticas de segurança para módulos. **Zero assumptions, zero hallucinations** - apenas documentação oficial. --- ## Documentação Base - [Module Security](https://help.perfexcrm.com/module-security/) - [CodeIgniter Security](https://codeigniter.com/userguide3/libraries/security.html) --- ## 1. Prevenção de Acesso Directo **OBRIGATÓRIO em todos os ficheiros PHP:** ```php 403 Forbidden

Directory access is forbidden.

``` --- ## 3. Input Validation (CRÍTICO) ### Usar Input Class do CodeIgniter ```php // CORRECTO - Input class escapa automaticamente $name = $this->input->post('name'); $id = $this->input->get('id'); $data = $this->input->post(); // Array de todos os POST // ERRADO - Nunca usar $_POST/$_GET directamente $name = $_POST['name']; // VULNERÁVEL! ``` ### Sanitização Adicional ```php // Inteiros $id = (int) $this->input->post('id'); // Escape para output HTML $name = html_escape($this->input->post('name')); // Strip tags $clean = strip_tags($this->input->post('content')); // XSS clean (built-in) $safe = $this->security->xss_clean($this->input->post('data')); ``` --- ## 4. CSRF Protection O Perfex CRM tem CSRF activado por defeito. ### Em Formulários (OBRIGATÓRIO) ```php ``` **NUNCA usar HTML `
` directo:** ```html ``` ### Em AJAX (jQuery) jQuery do Perfex inclui CSRF automaticamente. Para outras bibliotecas: ```javascript // Obter token CSRF var csrfName = 'security->get_csrf_token_name(); ?>'; var csrfHash = 'security->get_csrf_hash(); ?>'; // Incluir em requests $.ajax({ url: admin_url + 'meu_modulo/ajax_save', type: 'POST', data: { [csrfName]: csrfHash, name: $('#name').val() } }); ``` ### Excluir URLs de CSRF (v2.9.0+) Para webhooks que não podem incluir CSRF: ```php // modules/meu_modulo/config/csrf_exclude_uris.php db->where('id', $id); $this->db->where('status', $status); $result = $this->db->get(db_prefix() . 'meu_modulo')->result(); // CORRECTO - Binding de parâmetros $sql = "SELECT * FROM " . db_prefix() . "meu_modulo WHERE id = ? AND status = ?"; $result = $this->db->query($sql, [$id, $status])->result(); ``` ### NUNCA Concatenar Input ```php // ERRADO - SQL Injection vulnerável! $id = $_GET['id']; $sql = "SELECT * FROM tblmeu_modulo WHERE id = " . $id; // ERRADO - Mesmo com input class $id = $this->input->get('id'); $sql = "SELECT * FROM tblmeu_modulo WHERE id = " . $id; // VULNERÁVEL! ``` --- ## 6. XSS Prevention ### Em Views (SEMPRE) ```php name); ?> name; ?> ``` ### Função html_escape() ```php // Texto simples echo html_escape($string); // Para atributos HTML echo html_escape($string, true); ``` --- ## 7. File Upload Security ```php public function upload() { // Configurar upload $config['upload_path'] = './uploads/meu_modulo/'; $config['allowed_types'] = 'pdf|doc|docx|xls|xlsx'; // NUNCA permitir php! $config['max_size'] = 2048; // KB $config['encrypt_name'] = true; // Nome aleatório $this->load->library('upload', $config); if (!$this->upload->do_upload('ficheiro')) { // Erro $error = $this->upload->display_errors(); set_alert('danger', $error); } else { // Sucesso $data = $this->upload->data(); $filename = $data['file_name']; } } ``` ### Tipos Permitidos (Seguros) ```php // Documentos 'pdf|doc|docx|xls|xlsx|ppt|pptx|txt|csv' // Imagens 'gif|jpg|jpeg|png|webp' // NUNCA permitir 'php|php3|php4|php5|phtml|exe|sh|bat|js|html' ``` --- ## 8. Verificação de Ownership Sempre verificar se o utilizador tem acesso ao recurso: ```php public function view($id) { $item = $this->meu_modulo_model->get($id); // Verificar se existe if (!$item) { show_404(); } // Se for área cliente, verificar ownership if (!is_staff_logged_in()) { if ($item->client_id != get_client_user_id()) { show_404(); // Não revelar que existe } } // Ou para staff com view_own apenas if (!is_admin() && !staff_can('view_all', 'meu_modulo')) { if ($item->created_by != get_staff_user_id()) { access_denied('meu_modulo'); } } // ... mostrar dados } ``` --- ## 9. Session Security ```php // Regenerar session após login (já feito pelo Perfex) $this->session->sess_regenerate(); // Destruir session $this->session->sess_destroy(); // Guardar dados em session $this->session->set_userdata('key', 'value'); // Ler dados da session $value = $this->session->userdata('key'); ``` --- ## 10. Password Handling **NUNCA guardar passwords em plain text.** ```php // Hash password (se necessário no módulo) $hashed = password_hash($password, PASSWORD_DEFAULT); // Verificar password if (password_verify($input_password, $stored_hash)) { // Válido } ``` --- ## Checklist de Segurança ### Ficheiros ``` [ ] defined('BASEPATH') em todos os PHP [ ] index.html em todas as pastas [ ] Nenhum ficheiro executável em uploads ``` ### Input/Output ``` [ ] $this->input->post/get para todos os inputs [ ] html_escape() em todos os outputs [ ] Query Builder para todas as queries [ ] form_open() para todos os formulários ``` ### Acesso ``` [ ] staff_can() antes de operações [ ] Ownership verificado para dados de cliente [ ] CSRF token em formulários e AJAX [ ] Tipos de ficheiro restritos em uploads ``` --- ## Exemplo Seguro Completo ### Controller ```php load->model('meu_modulo/meu_modulo_model'); } public function save() { // 1. Verificar permissão if (!staff_can('create', 'meu_modulo')) { access_denied('meu_modulo'); } // 2. Verificar se é POST (CSRF verificado automaticamente) if (!$this->input->post()) { redirect(admin_url('meu_modulo')); } // 3. Validar e sanitizar input $data = [ 'name' => trim($this->input->post('name')), 'description' => $this->input->post('description'), 'amount' => (float) $this->input->post('amount'), 'client_id' => (int) $this->input->post('client_id'), ]; // 4. Validação de negócio if (empty($data['name'])) { set_alert('danger', _l('field_required', _l('name'))); redirect(admin_url('meu_modulo/create')); } // 5. Guardar via model (usa Query Builder) $id = $this->meu_modulo_model->add($data); if ($id) { set_alert('success', _l('added_successfully')); } else { set_alert('danger', _l('error_occurred')); } redirect(admin_url('meu_modulo')); } } ``` ### View ```php
``` --- ## Anti-Patterns (NUNCA FAZER) | Anti-Pattern | Risco | Alternativa | |--------------|-------|-------------| | `$_POST`/`$_GET` directo | XSS, Injection | `$this->input->post/get` | | Echo sem escape | XSS | `html_escape()` | | SQL concatenado | SQL Injection | Query Builder | | `` HTML | CSRF bypass | `form_open()` | | Upload sem validação | RCE | `allowed_types` restrito | | Sem verificar ownership | Data breach | Validar sempre | --- **Versão:** 1.0.0 | **Autor:** Descomplicar® **Fonte:** help.perfexcrm.com/module-security