feat: adiciona 12 plugins Descomplicar ao marketplace
Plugins: automacao, crm-ops, design-media, dev-tools, gestao, infraestrutura, marketing, negocio, perfex-dev, project-manager, wordpress + hello-plugin (existente). Totais: 83 skills, 44 agents, 12 datasets.json Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
468
perfex-dev/skills/perfex-security/SKILL.md
Normal file
468
perfex-dev/skills/perfex-security/SKILL.md
Normal file
@@ -0,0 +1,468 @@
|
||||
---
|
||||
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
|
||||
<?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:**
|
||||
|
||||
```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
|
||||
|
||||
```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
|
||||
<?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:**
|
||||
|
||||
```html
|
||||
<!-- ERRADO - Sem CSRF token -->
|
||||
<form action="..." method="post">
|
||||
```
|
||||
|
||||
### Em AJAX (jQuery)
|
||||
|
||||
jQuery do Perfex inclui CSRF automaticamente. Para outras bibliotecas:
|
||||
|
||||
```javascript
|
||||
// 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:
|
||||
|
||||
```php
|
||||
// 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)
|
||||
|
||||
```php
|
||||
// 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
|
||||
|
||||
```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
|
||||
<!-- 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()
|
||||
|
||||
```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
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Meu_modulo extends AdminController
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->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
|
||||
<?php defined('BASEPATH') or exit('No direct script access allowed'); ?>
|
||||
<?php init_head(); ?>
|
||||
|
||||
<div id="wrapper">
|
||||
<div class="content">
|
||||
<div class="panel_s">
|
||||
<div class="panel-body">
|
||||
|
||||
<?php echo form_open(admin_url('meu_modulo/save')); ?>
|
||||
|
||||
<div class="form-group">
|
||||
<label><?php echo _l('name'); ?></label>
|
||||
<input type="text"
|
||||
name="name"
|
||||
class="form-control"
|
||||
value="<?php echo isset($item) ? html_escape($item->name) : ''; ?>"
|
||||
required>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<?php echo _l('save'); ?>
|
||||
</button>
|
||||
|
||||
<?php echo form_close(); ?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php init_tail(); ?>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 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 |
|
||||
| `<form>` 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
|
||||
Reference in New Issue
Block a user