5.0 KiB
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'];
}
}