Files
claude-plugins/perfex-dev/skills/perfex-security/SKILL.md
T

5.0 KiB

name, description, layer
name description layer
perfex-security Segurança para módulos Perfex CRM — validação de input, CSRF, prevenção XSS e protecção contra directory traversal. Baseado apenas na documentação oficial. wiki

/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


1. Prevenção de Acesso Directo

OBRIGATÓRIO em todos os ficheiros PHP:

<?php

defined('BASEPATH') or exit('No direct script access allowed');

// Resto do código

Isto previne execução directa via URL.


2. Prevenção de Directory Listing

Incluir index.html vazio em todas as pastas:

modules/meu_modulo/
├── index.html          ← OBRIGATÓRIO
├── controllers/
│   └── index.html      ← OBRIGATÓRIO
├── models/
│   └── index.html      ← OBRIGATÓRIO
├── views/
│   └── index.html      ← OBRIGATÓRIO
└── libraries/
    └── index.html      ← OBRIGATÓRIO

Conteúdo do index.html:

<!DOCTYPE html>
<html>
<head>
    <title>403 Forbidden</title>
</head>
<body>
    <p>Directory access is forbidden.</p>
</body>
</html>

3. Input Validation (CRÍTICO)

Usar Input Class do CodeIgniter

// 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

// 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 echo form_open(admin_url('meu_modulo/save')); ?>
    <!-- form_open() gera token CSRF automaticamente -->
    <input type="text" name="name">
    <button type="submit">Guardar</button>
<?php echo form_close(); ?>

NUNCA usar HTML <form> directo:

<!-- ERRADO - Sem CSRF token -->
<form action="..." method="post">

Em AJAX (jQuery)

jQuery do Perfex inclui CSRF automaticamente. Para outras bibliotecas:

// Obter token CSRF
var csrfName = '<?php echo $this->security->get_csrf_token_name(); ?>';
var csrfHash = '<?php echo $this->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:

// modules/meu_modulo/config/csrf_exclude_uris.php

<?php

defined('BASEPATH') or exit('No direct script access allowed');

return [
    'meu_modulo/webhook',
    'meu_modulo/api/.*',  // Regex suportado
];

5. SQL Injection Prevention

Usar Query Builder (SEMPRE)

// CORRECTO - Query Builder escapa parâmetros
$this->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

// 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)

<!-- CORRECTO - Escape HTML -->
<td><?php echo html_escape($item->name); ?></td>
<input value="<?php echo html_escape($item->value); ?>">

<!-- ERRADO - XSS vulnerável -->
<td><?php echo $item->name; ?></td>

Função html_escape()

// Texto simples
echo html_escape($string);

// Para atributos HTML
echo html_escape($string, true);

7. File Upload Security

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