feat: refactor 30+ skills to Anthropic progressive disclosure pattern
- All SKILL.md files now <500 lines (avg reduction 69%) - Detailed content extracted to references/ subdirectories - Frontmatter standardised: only name + description (Anthropic standard) - New skills: brand-guidelines, spec-coauthor, report-templates, skill-creator - Design skills: anti-slop guidelines, premium-proposals reference - Removed non-standard frontmatter fields (triggers, version, author, category) Plugins affected: infraestrutura, marketing, dev-tools, crm-ops, gestao, core-tools, negocio, perfex-dev, wordpress, design-media Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
356
wordpress/skills/wp-hardening/SKILL.md
Normal file
356
wordpress/skills/wp-hardening/SKILL.md
Normal file
@@ -0,0 +1,356 @@
|
||||
---
|
||||
name: wp-hardening
|
||||
description: Aplicar hardening de seguranca standard a sites WordPress via SSH. Desactiva XML-RPC, file editing, directory listing, esconde versao WP, verifica permissoes e security headers.
|
||||
---
|
||||
|
||||
# /wp-hardening - Hardening WordPress
|
||||
|
||||
Aplica medidas de hardening standard a sites WordPress no servidor CWP (176.9.3.158).
|
||||
|
||||
> **Nota:** Esta skill APLICA alteracoes. Para auditar sem alterar, usar `/security-check`.
|
||||
|
||||
## Contexto NotebookLM
|
||||
|
||||
ANTES de executar, consultar notebook para contexto:
|
||||
|
||||
| Notebook | ID | Consultar quando |
|
||||
|----------|-----|-----------------|
|
||||
| WordPress e Elementor | 5be0d1a6 | Sempre |
|
||||
|
||||
```
|
||||
mcp__notebooklm__notebook_query({
|
||||
notebook_id: "5be0d1a6-00f2-4cd9-b835-978cb7721601",
|
||||
query: "wordpress security hardening best practices"
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Uso
|
||||
|
||||
```
|
||||
/wp-hardening descomplicar.pt
|
||||
/wp-hardening all # todos os 16 sites
|
||||
/wp-hardening descomplicar.pt --dry # apenas verificar, sem aplicar
|
||||
```
|
||||
|
||||
**Argumento:** dominio do site (ver tabela de sites em /wp-update) ou `all`.
|
||||
**Flag `--dry`:** apenas verifica estado actual sem aplicar alteracoes.
|
||||
|
||||
---
|
||||
|
||||
## Sites WordPress no servidor
|
||||
|
||||
| Conta | Site | Path |
|
||||
|-------|------|------|
|
||||
| carstuff | carstuff.pt | /home/carstuff/public_html |
|
||||
| ealmeida | descomplicar.pt | /home/ealmeida/public_html |
|
||||
| ealmeida | emanuelalmeida.pt | /home/ealmeida/emanuelalmeida.pt |
|
||||
| ealmeida | ecommerce.descomplicar.pt | /home/ealmeida/ecommerce.descomplicar.pt |
|
||||
| ealmeida | ecommerce-demo.descomplicar.pt | /home/ealmeida/ecommerce-demo.descomplicar.pt |
|
||||
| ealmeida | starter.descomplicar.pt | /home/ealmeida/starter.descomplicar.pt |
|
||||
| ealmeida | care.descomplicar.pt | /home/ealmeida/care.descomplicar.pt |
|
||||
| ealmeida | e-commerce.descomplicar.pt | /home/ealmeida/e-commerce.descomplicar.pt |
|
||||
| espiral | espiralsenior.pt | /home/espiral/public_html |
|
||||
| espiral | dev.espiralsenior.pt | /home/espiral/dev.espiralsenior.pt |
|
||||
| familycl | familyclinic.pt | /home/familycl/public_html |
|
||||
| ignition | ignitionvortex.pt | /home/ignition/public_html |
|
||||
| karate | karateclubedegaia.com | /home/karate/karateclubedegaia.com |
|
||||
| sintri | sintricare.com.pt | /home/sintri/public_html |
|
||||
| solarfv | solarfvengenharia.com | /home/solarfv/public_html |
|
||||
| wtc | watercontrol.pt | /home/wtc/public_html |
|
||||
|
||||
---
|
||||
|
||||
## Execucao
|
||||
|
||||
### Passo 0: Identificar site e path
|
||||
|
||||
Mapear o dominio fornecido para o path e conta do servidor usando a tabela acima.
|
||||
|
||||
```bash
|
||||
SITE="dominio.pt"
|
||||
WP_PATH="/home/USER/public_html"
|
||||
WP_USER="user"
|
||||
```
|
||||
|
||||
### Passo 1: Verificar estado actual (antes)
|
||||
|
||||
Executar via `mcp__ssh-unified__ssh_execute` no servidor `cwp`:
|
||||
|
||||
```bash
|
||||
# 1. XML-RPC activo?
|
||||
curl -s -o /dev/null -w "%{http_code}" -X POST "${SITE}/xmlrpc.php" -d '<?xml version="1.0"?><methodCall><methodName>system.listMethods</methodName></methodCall>'
|
||||
|
||||
# 2. DISALLOW_FILE_EDIT definido?
|
||||
grep -c "DISALLOW_FILE_EDIT" ${WP_PATH}/wp-config.php
|
||||
|
||||
# 3. Permissoes directórios (esperado: 755)
|
||||
find ${WP_PATH} -type d -not -perm 755 | head -10
|
||||
|
||||
# 4. Permissoes ficheiros (esperado: 644)
|
||||
find ${WP_PATH} -type f -not -perm 644 -not -name "wp-config.php" | head -10
|
||||
|
||||
# 5. Versao WP exposta no HTML?
|
||||
curl -s ${SITE} | grep -o 'content="WordPress [0-9.]*"' | head -1
|
||||
|
||||
# 6. Versao WP exposta no feed?
|
||||
curl -s ${SITE}/feed/ | grep -o '<generator>.*</generator>' | head -1
|
||||
|
||||
# 7. Directory listing activo?
|
||||
curl -s -o /dev/null -w "%{http_code}" ${SITE}/wp-content/uploads/
|
||||
|
||||
# 8. wp-config.php permissoes (esperado: 400 ou 440)
|
||||
stat -c "%a" ${WP_PATH}/wp-config.php
|
||||
|
||||
# 9. .htaccess security headers?
|
||||
grep -c "X-Frame-Options\|X-Content-Type-Options\|X-XSS-Protection\|Referrer-Policy\|Content-Security-Policy\|Strict-Transport-Security" ${WP_PATH}/.htaccess 2>/dev/null
|
||||
|
||||
# 10. debug.log exposto?
|
||||
test -f ${WP_PATH}/wp-content/debug.log && echo "EXPOSTO" || echo "OK"
|
||||
```
|
||||
|
||||
Registar cada resultado como ANTES.
|
||||
|
||||
### Passo 2: Aplicar hardening (se nao --dry)
|
||||
|
||||
> **Regra:** Fazer backup de cada ficheiro ANTES de alterar.
|
||||
|
||||
#### 2.1 Desactivar XML-RPC
|
||||
|
||||
```bash
|
||||
# Backup .htaccess
|
||||
cp ${WP_PATH}/.htaccess ${WP_PATH}/.htaccess.bak.$(date +%Y%m%d)
|
||||
|
||||
# Adicionar bloqueio XML-RPC ao .htaccess (antes de # BEGIN WordPress)
|
||||
sed -i '/# BEGIN WordPress/i \
|
||||
# BEGIN Block XML-RPC\
|
||||
<Files xmlrpc.php>\
|
||||
Require all denied\
|
||||
</Files>\
|
||||
# END Block XML-RPC\
|
||||
' ${WP_PATH}/.htaccess
|
||||
```
|
||||
|
||||
**Excepcao:** Se o site usa JetPack ou aplicacao mobile WP, NAO desactivar XML-RPC. Verificar primeiro:
|
||||
```bash
|
||||
sudo -u ${WP_USER} wp plugin list --status=active --path=${WP_PATH} | grep -i "jetpack"
|
||||
```
|
||||
|
||||
#### 2.2 Desactivar file editing (DISALLOW_FILE_EDIT)
|
||||
|
||||
```bash
|
||||
# Backup wp-config.php
|
||||
cp ${WP_PATH}/wp-config.php ${WP_PATH}/wp-config.php.bak.$(date +%Y%m%d)
|
||||
|
||||
# Adicionar se nao existir
|
||||
grep -q "DISALLOW_FILE_EDIT" ${WP_PATH}/wp-config.php || \
|
||||
sed -i "/\/\* That's all, stop editing/i define('DISALLOW_FILE_EDIT', true);" ${WP_PATH}/wp-config.php
|
||||
```
|
||||
|
||||
#### 2.3 Corrigir permissoes
|
||||
|
||||
```bash
|
||||
# Directorios: 755
|
||||
find ${WP_PATH} -type d -exec chmod 755 {} \;
|
||||
|
||||
# Ficheiros: 644
|
||||
find ${WP_PATH} -type f -exec chmod 644 {} \;
|
||||
|
||||
# wp-config.php: 440 (leitura apenas para owner e grupo)
|
||||
chmod 440 ${WP_PATH}/wp-config.php
|
||||
|
||||
# Corrigir ownership
|
||||
chown -R ${WP_USER}:${WP_USER} ${WP_PATH}
|
||||
```
|
||||
|
||||
#### 2.4 Esconder versao WordPress
|
||||
|
||||
```bash
|
||||
# Adicionar ao functions.php do tema activo (via wp-cli)
|
||||
THEME_PATH=$(sudo -u ${WP_USER} wp theme path --path=${WP_PATH})/$(sudo -u ${WP_USER} wp theme list --status=active --field=name --path=${WP_PATH})
|
||||
|
||||
# Verificar se ja tem o filtro
|
||||
grep -q "remove_action.*wp_head.*wp_generator" ${THEME_PATH}/functions.php 2>/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
# Alternativa robusta: usar mu-plugin (nao se perde em updates de tema)
|
||||
mkdir -p ${WP_PATH}/wp-content/mu-plugins
|
||||
cat > ${WP_PATH}/wp-content/mu-plugins/dsc-hardening.php << 'MUEOF'
|
||||
<?php
|
||||
/**
|
||||
* Descomplicar - WordPress Hardening
|
||||
* Esconde versao WP, desactiva XML-RPC via filtro, remove headers desnecessarios.
|
||||
*/
|
||||
|
||||
// Esconder versao WP
|
||||
remove_action('wp_head', 'wp_generator');
|
||||
add_filter('the_generator', '__return_empty_string');
|
||||
|
||||
// Remover versao dos scripts e styles
|
||||
function dsc_remove_version_scripts_styles($src) {
|
||||
if (strpos($src, 'ver=')) {
|
||||
$src = remove_query_arg('ver', $src);
|
||||
}
|
||||
return $src;
|
||||
}
|
||||
add_filter('style_loader_src', 'dsc_remove_version_scripts_styles', 9999);
|
||||
add_filter('script_loader_src', 'dsc_remove_version_scripts_styles', 9999);
|
||||
|
||||
// Desactivar XML-RPC via filtro (complemento ao .htaccess)
|
||||
add_filter('xmlrpc_enabled', '__return_false');
|
||||
|
||||
// Remover link do REST API do header (opcional, reduz surface)
|
||||
remove_action('wp_head', 'rest_output_link_wp_head');
|
||||
remove_action('wp_head', 'wp_oembed_add_discovery_links');
|
||||
remove_action('wp_head', 'rsd_link');
|
||||
remove_action('wp_head', 'wlwmanifest_link');
|
||||
remove_action('wp_head', 'wp_shortlink_wp_head');
|
||||
MUEOF
|
||||
chown ${WP_USER}:${WP_USER} ${WP_PATH}/wp-content/mu-plugins/dsc-hardening.php
|
||||
chmod 644 ${WP_PATH}/wp-content/mu-plugins/dsc-hardening.php
|
||||
fi
|
||||
```
|
||||
|
||||
#### 2.5 Desactivar directory listing
|
||||
|
||||
```bash
|
||||
# Adicionar ao .htaccess se nao existir
|
||||
grep -q "Options -Indexes" ${WP_PATH}/.htaccess || \
|
||||
sed -i '1i Options -Indexes' ${WP_PATH}/.htaccess
|
||||
```
|
||||
|
||||
#### 2.6 Security headers no .htaccess
|
||||
|
||||
```bash
|
||||
# Verificar e adicionar headers em falta
|
||||
if ! grep -q "X-Frame-Options" ${WP_PATH}/.htaccess; then
|
||||
cat >> ${WP_PATH}/.htaccess << 'HTEOF'
|
||||
|
||||
# BEGIN Security Headers
|
||||
<IfModule mod_headers.c>
|
||||
Header always set X-Frame-Options "SAMEORIGIN"
|
||||
Header always set X-Content-Type-Options "nosniff"
|
||||
Header always set X-XSS-Protection "1; mode=block"
|
||||
Header always set Referrer-Policy "strict-origin-when-cross-origin"
|
||||
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
|
||||
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
|
||||
</IfModule>
|
||||
# END Security Headers
|
||||
HTEOF
|
||||
fi
|
||||
```
|
||||
|
||||
#### 2.7 Proteger debug.log
|
||||
|
||||
```bash
|
||||
# Se debug.log existe, bloquear acesso
|
||||
if [ -f "${WP_PATH}/wp-content/debug.log" ]; then
|
||||
cat >> ${WP_PATH}/wp-content/.htaccess << 'DLEOF'
|
||||
<Files debug.log>
|
||||
Require all denied
|
||||
</Files>
|
||||
DLEOF
|
||||
fi
|
||||
|
||||
# Desactivar WP_DEBUG se estiver activo em producao
|
||||
grep -q "define.*WP_DEBUG.*true" ${WP_PATH}/wp-config.php && \
|
||||
sed -i "s/define.*'WP_DEBUG'.*true.*/define('WP_DEBUG', false);/" ${WP_PATH}/wp-config.php
|
||||
```
|
||||
|
||||
### Passo 3: Verificar estado (depois)
|
||||
|
||||
Re-executar todos os testes do Passo 1 e registar como DEPOIS.
|
||||
|
||||
### Passo 4: Verificar site funcional
|
||||
|
||||
```bash
|
||||
# Verificar que o site responde correctamente
|
||||
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" https://${SITE})
|
||||
echo "HTTP: ${HTTP_CODE}"
|
||||
|
||||
# Verificar conteudo por erros criticos
|
||||
curl -s https://${SITE} | grep -i "critical error\|fatal error\|error establishing" | head -3
|
||||
```
|
||||
|
||||
**Se o site reportar erro apos hardening:** reverter imediatamente usando os backups (.bak).
|
||||
|
||||
### Passo 5: Corrigir ownership final
|
||||
|
||||
```bash
|
||||
chown -R ${WP_USER}:${WP_USER} ${WP_PATH}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Output Template
|
||||
|
||||
```markdown
|
||||
# WP Hardening Report - [site.pt]
|
||||
|
||||
**Data:** YYYY-MM-DD
|
||||
**Modo:** Aplicado / Dry Run
|
||||
|
||||
---
|
||||
|
||||
## Checklist Hardening
|
||||
|
||||
| # | Item | Antes | Depois | Accao |
|
||||
|---|------|-------|--------|-------|
|
||||
| 1 | XML-RPC desactivado | / | / | .htaccess + mu-plugin |
|
||||
| 2 | File editing desactivado | / | / | wp-config.php |
|
||||
| 3 | Permissoes dirs (755) | / | / | chmod recursivo |
|
||||
| 4 | Permissoes ficheiros (644) | / | / | chmod recursivo |
|
||||
| 5 | Versao WP escondida | / | / | mu-plugin |
|
||||
| 6 | Directory listing desactivado | / | / | .htaccess |
|
||||
| 7 | Security headers | / | / | .htaccess |
|
||||
| 8 | wp-config.php (440) | / | / | chmod |
|
||||
| 9 | debug.log protegido | / | / | .htaccess |
|
||||
| 10 | WP_DEBUG desactivado | / | / | wp-config.php |
|
||||
|
||||
---
|
||||
|
||||
## Ficheiros alterados
|
||||
|
||||
- `wp-config.php` (DISALLOW_FILE_EDIT, WP_DEBUG)
|
||||
- `.htaccess` (XML-RPC, directory listing, security headers)
|
||||
- `wp-content/mu-plugins/dsc-hardening.php` (criado)
|
||||
|
||||
## Backups criados
|
||||
|
||||
- `.htaccess.bak.YYYYMMDD`
|
||||
- `wp-config.php.bak.YYYYMMDD`
|
||||
|
||||
## Verificacao pos-hardening
|
||||
|
||||
- HTTP: [200/301/etc]
|
||||
- Erros criticos: [Nenhum / Lista]
|
||||
|
||||
---
|
||||
|
||||
*Gerado via /wp-hardening v1.0.0 - YYYY-MM-DD*
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Notas importantes
|
||||
|
||||
1. **Backups obrigatorios** antes de qualquer alteracao
|
||||
2. **mu-plugin** preferido sobre functions.php (sobrevive a updates de tema)
|
||||
3. **JetPack** requer XML-RPC — verificar SEMPRE antes de desactivar
|
||||
4. **Content-Security-Policy** nao incluido como header standard porque varia por site. Adicionar manualmente se necessario
|
||||
5. **Reverter:** os backups `.bak.YYYYMMDD` permitem rollback rapido
|
||||
6. **Ownership:** SEMPRE `chown -R USER:USER` no final (regra #11)
|
||||
|
||||
---
|
||||
|
||||
## Changelog
|
||||
|
||||
### v1.0.0 (2026-03-12)
|
||||
- Versao inicial
|
||||
- 10 verificacoes de hardening
|
||||
- Modo dry run (--dry)
|
||||
- mu-plugin dsc-hardening.php para medidas PHP
|
||||
- Security headers standard no .htaccess
|
||||
- Backup automatico antes de alteracoes
|
||||
- Verificacao pos-hardening com rollback
|
||||
- Tarefa Desk CRM #443 (Projecto #65, Discussao #33)
|
||||
Reference in New Issue
Block a user