feat(mitmproxy): Add WAF Filters UI to LuCI dashboard

- Add new WAF Filters tab displaying 10 detection categories
- Categories: sqli, xss, lfi, rce, cve_2024, scanners, webmail, api_abuse, nextcloud, roundcube
- Toggle enable/disable per category with live updates
- Expandable rules tables with patterns, descriptions, CVE links
- Summary stats: total categories, active filters, rule count
- RPCD methods: get_waf_rules, toggle_waf_category
- Update menu entry and ACL permissions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-02-17 16:02:58 +01:00
parent 00f584e6a0
commit 75b85080fa
6 changed files with 280 additions and 4 deletions

View File

@ -2271,3 +2271,22 @@ git checkout HEAD -- index.html
- Ports: 25, 143, 587, 993
- Mail storage: `/var/mail/` with vmail user (uid 5000)
- Old Alpine backup: `/srv/lxc/mailserver-alpine-backup/`
### 2026-02-17: mitmproxy WAF Filters UI
**New LuCI View:**
- Added "WAF Filters" tab to mitmproxy security interface
- Displays all 10 WAF detection categories with enable/disable toggles
- Categories: sqli, xss, lfi, rce, cve_2024, scanners, webmail, api_abuse, nextcloud, roundcube
- Summary stats: total categories, active filters, rule count
- Expandable rules tables showing patterns, descriptions, CVE links
**RPCD Methods:**
- `get_waf_rules` - Returns WAF rules JSON from `/srv/mitmproxy/waf-rules.json`
- `toggle_waf_category` - Enable/disable category in rules file
**Files Created/Modified:**
- `luci-app-mitmproxy/htdocs/.../view/mitmproxy/waf-filters.js` (new)
- `luci-app-mitmproxy/root/usr/libexec/rpcd/luci.mitmproxy` (added methods)
- `luci-app-mitmproxy/root/usr/share/luci/menu.d/luci-app-mitmproxy.json` (menu entry)
- `luci-app-mitmproxy/root/usr/share/rpcd/acl.d/luci-app-mitmproxy.json` (ACL permissions)

View File

@ -64,6 +64,14 @@ _Last updated: 2026-02-17 (v0.21.0 - Nextcloud LXC + WebRadio)_
### Just Completed (2026-02-17)
- **mitmproxy WAF Filters UI** — DONE (2026-02-17)
- Added new "WAF Filters" tab to mitmproxy LuCI interface
- Displays 10 filter categories: sqli, xss, lfi, rce, cve_2024, scanners, webmail, api_abuse, nextcloud, roundcube
- Toggle enable/disable per category with live updates
- Expandable rules tables showing patterns, descriptions, CVE links
- Summary stats: total categories, active filters, rule count
- RPCD methods: get_waf_rules, toggle_waf_category
- **Security KISS Dashboard Enhancements** — DONE (2026-02-17)
- Added ndpid (nDPI daemon) to service status monitoring
- Added Wazuh SIEM to security services list (earlier today)

View File

@ -0,0 +1,215 @@
'use strict';
'require view';
'require rpc';
'require ui';
'require secubox/kiss-theme';
var callGetWafRules = rpc.declare({
object: 'luci.mitmproxy',
method: 'get_waf_rules',
expect: {}
});
var callToggleWafCategory = rpc.declare({
object: 'luci.mitmproxy',
method: 'toggle_waf_category',
params: ['category', 'enabled']
});
function severityColor(sev) {
return {
critical: '#e74c3c',
high: '#e67e22',
medium: '#f39c12',
low: '#3498db'
}[sev] || '#666';
}
function severityBadge(sev) {
return E('span', {
'style': 'background: ' + severityColor(sev) + '; color: white; padding: 2px 8px; border-radius: 4px; font-size: 11px; text-transform: uppercase;'
}, sev);
}
return view.extend({
load: function() {
return callGetWafRules().catch(function() { return {}; });
},
render: function(data) {
var self = this;
var rulesData = data || {};
// Handle both top-level categories and wrapped in "categories" object
var rules = rulesData.categories || rulesData;
var categories = Object.keys(rules).filter(function(k) {
return k !== '_meta' && typeof rules[k] === 'object' && rules[k].patterns;
});
// Count totals
var totalRules = 0;
var enabledCategories = 0;
categories.forEach(function(cat) {
totalRules += (rules[cat].patterns || []).length;
if (rules[cat].enabled !== false) enabledCategories++;
});
var content = [
// Header
E('div', { 'style': 'margin-bottom: 24px;' }, [
E('h2', { 'style': 'font-size: 24px; font-weight: 700; margin: 0 0 8px 0;' }, '🛡️ WAF Filters'),
E('p', { 'style': 'color: var(--kiss-muted); margin: 0;' }, 'Web Application Firewall detection rules')
]),
// Summary Stats
E('div', { 'class': 'kiss-grid kiss-grid-auto', 'style': 'margin-bottom: 24px;' }, [
E('div', { 'class': 'kiss-stat' }, [
E('div', { 'class': 'kiss-stat-value', 'style': 'color: #3498db;' }, String(categories.length)),
E('div', { 'class': 'kiss-stat-label' }, 'Categories')
]),
E('div', { 'class': 'kiss-stat' }, [
E('div', { 'class': 'kiss-stat-value', 'style': 'color: #27ae60;' }, String(enabledCategories)),
E('div', { 'class': 'kiss-stat-label' }, 'Active')
]),
E('div', { 'class': 'kiss-stat' }, [
E('div', { 'class': 'kiss-stat-value', 'style': 'color: #e67e22;' }, String(totalRules)),
E('div', { 'class': 'kiss-stat-label' }, 'Rules')
])
]),
// Categories
E('div', { 'class': 'cbi-section' }, [
E('h3', {}, _('Filter Categories')),
E('div', { 'class': 'cbi-section-node' },
categories.length > 0 ? categories.map(function(catName) {
var cat = rules[catName];
var catRules = cat.patterns || [];
var isEnabled = cat.enabled !== false;
var severity = cat.severity || 'medium';
return E('div', {
'class': 'kiss-card',
'style': 'margin-bottom: 16px; border-left: 4px solid ' + severityColor(severity) + ';'
}, [
// Category Header
E('div', {
'style': 'display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px;'
}, [
E('div', {}, [
E('strong', { 'style': 'font-size: 16px; text-transform: uppercase;' }, catName.replace(/_/g, ' ')),
' ',
severityBadge(severity),
E('span', {
'style': 'margin-left: 8px; font-size: 12px; color: var(--kiss-muted);'
}, '(' + catRules.length + ' rules)')
]),
E('label', { 'style': 'display: flex; align-items: center; cursor: pointer;' }, [
E('input', {
'type': 'checkbox',
'checked': isEnabled,
'style': 'width: 18px; height: 18px; margin-right: 8px;',
'data-category': catName,
'change': function(ev) {
var category = ev.target.dataset.category;
var enabled = ev.target.checked;
ui.showModal(_('Updating...'), [E('p', { 'class': 'spinning' }, _('Updating category...'))]);
callToggleWafCategory(category, enabled).then(function(res) {
ui.hideModal();
if (res && res.success) {
ui.addNotification(null, E('p', {},
category + ' ' + (enabled ? _('enabled') : _('disabled'))), 'success');
} else {
ui.addNotification(null, E('p', {},
_('Failed: ') + (res.error || 'Unknown error')), 'error');
ev.target.checked = !enabled; // Revert
}
}).catch(function(err) {
ui.hideModal();
ui.addNotification(null, E('p', {}, _('Error: ') + err), 'error');
ev.target.checked = !enabled;
});
}
}),
E('span', { 'style': 'font-size: 13px; color: ' + (isEnabled ? '#27ae60' : '#95a5a6') + ';' },
isEnabled ? _('Enabled') : _('Disabled'))
])
]),
// Rules Table
catRules.length > 0 ? E('details', { 'style': 'margin-top: 8px;' }, [
E('summary', {
'style': 'cursor: pointer; color: var(--kiss-muted); font-size: 13px; padding: 8px 0;'
}, _('Show rules')),
E('table', { 'class': 'table', 'style': 'font-size: 12px; margin-top: 8px;' }, [
E('tr', { 'class': 'tr cbi-section-table-titles' }, [
E('th', { 'class': 'th', 'style': 'width: 60px;' }, _('ID')),
E('th', { 'class': 'th' }, _('Pattern')),
E('th', { 'class': 'th', 'style': 'width: 200px;' }, _('Description')),
E('th', { 'class': 'th', 'style': 'width: 100px;' }, _('CVE'))
])
].concat(catRules.map(function(rule, idx) {
// Decode placeholder strings back to original
var pattern = (rule.pattern || '')
.replace(/QUOTE/g, "'")
.replace(/DQUOTE/g, '"')
.replace(/x27/g, "'");
var desc = rule.desc || rule.description || '-';
var cve = rule.cve || '-';
return E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td', 'style': 'font-family: monospace; color: #666;' },
rule.id || String(idx + 1)),
E('td', {
'class': 'td',
'style': 'font-family: monospace; font-size: 11px; max-width: 400px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;',
'title': pattern
}, pattern),
E('td', { 'class': 'td', 'style': 'color: var(--kiss-muted);' }, desc),
E('td', { 'class': 'td' },
cve !== '-' ? E('a', {
'href': 'https://nvd.nist.gov/vuln/detail/' + cve,
'target': '_blank',
'style': 'color: #e74c3c; font-size: 11px;'
}, cve) : E('span', { 'style': 'color: #999;' }, '-'))
]);
})))
]) : E('p', { 'style': 'color: var(--kiss-muted); font-size: 12px; margin: 8px 0 0 0;' },
_('No rules defined'))
]);
}) : E('div', { 'style': 'text-align: center; padding: 40px; color: var(--kiss-muted);' }, [
E('div', { 'style': 'font-size: 48px; margin-bottom: 16px;' }, '🛡️'),
E('p', {}, _('No WAF rules loaded')),
E('p', { 'style': 'font-size: 12px;' }, _('WAF rules file not found at /srv/mitmproxy/waf-rules.json'))
])
)
]),
// Info Card
E('div', { 'class': 'kiss-card' }, [
E('div', { 'class': 'kiss-card-title' }, '📖 ' + _('Information')),
E('div', {}, [
E('p', { 'style': 'color: var(--kiss-muted); margin-bottom: 12px;' },
_('WAF filters detect and block common web attacks. Each category targets a specific type of threat.')),
E('ul', { 'style': 'color: var(--kiss-muted); margin: 0; padding-left: 20px;' }, [
E('li', {}, E('strong', {}, 'SQLi'), ' - SQL injection attempts'),
E('li', {}, E('strong', {}, 'XSS'), ' - Cross-site scripting attacks'),
E('li', {}, E('strong', {}, 'LFI'), ' - Local file inclusion'),
E('li', {}, E('strong', {}, 'RCE'), ' - Remote code execution'),
E('li', {}, E('strong', {}, 'CVE'), ' - Known vulnerability exploits'),
E('li', {}, E('strong', {}, 'Scanners'), ' - Automated vulnerability scanners')
]),
E('p', { 'style': 'margin-top: 12px; color: var(--kiss-muted);' }, [
_('Rules file: '),
E('code', { 'style': 'font-size: 11px; background: #f0f0f0; padding: 2px 6px; border-radius: 3px;' },
'/srv/mitmproxy/waf-rules.json')
])
])
])
];
return KissTheme.wrap(content, 'admin/secubox/security/mitmproxy/waf-filters');
},
handleSaveApply: null,
handleSave: null,
handleReset: null
});

View File

@ -756,8 +756,34 @@ wan_clear() {
json_dump
}
get_waf_rules() {
local rules_file="/srv/mitmproxy/waf-rules.json"
if [ -f "$rules_file" ]; then
cat "$rules_file"
else
echo "{"error":"WAF rules file not found"}"
fi
}
toggle_waf_category() {
read -r input
local category=$(jsonfilter -s "$input" -e '@.category' 2>/dev/null)
local enabled=$(jsonfilter -s "$input" -e '@.enabled' 2>/dev/null)
local rules_file="/srv/mitmproxy/waf-rules.json"
if [ -z "$category" ]; then
echo '{"error":"Missing category"}'
return
fi
if [ -f "$rules_file" ] && command -v jq >/dev/null 2>&1; then
cp "$rules_file" "${rules_file}.bak"
jq ".categories.\"$category\".enabled = $enabled" "$rules_file" > "${rules_file}.tmp" && mv "${rules_file}.tmp" "$rules_file"
echo '{"success":true}'
else
echo '{"error":"Cannot update rules"}'
fi
}
list_methods() { cat <<'EOFM'
{"status":{},"status_cached":{},"settings":{},"save_settings":{"mode":"str","enabled":"bool","proxy_port":"int","web_port":"int","apply_now":"bool","wan_protection_enabled":"bool","wan_interface":"str"},"set_mode":{"mode":"str","apply_now":"bool"},"setup_firewall":{},"clear_firewall":{},"wan_setup":{},"wan_clear":{},"install":{},"start":{},"stop":{},"restart":{},"alerts":{},"threat_stats":{},"subdomain_metrics":{},"clear_alerts":{},"haproxy_enable":{},"haproxy_disable":{},"sync_routes":{},"bans":{},"unban":{"ip":"str"}}
{"status":{},"status_cached":{},"settings":{},"save_settings":{"mode":"str","enabled":"bool","proxy_port":"int","web_port":"int","apply_now":"bool","wan_protection_enabled":"bool","wan_interface":"str"},"set_mode":{"mode":"str","apply_now":"bool"},"setup_firewall":{},"clear_firewall":{},"wan_setup":{},"wan_clear":{},"install":{},"start":{},"stop":{},"restart":{},"alerts":{},"threat_stats":{},"subdomain_metrics":{},"clear_alerts":{},"haproxy_enable":{},"haproxy_disable":{},"sync_routes":{},"bans":{},"unban":{"ip":"str"},"get_waf_rules":{},"toggle_waf_category":{"category":"str","enabled":"bool"}}
EOFM
}
@ -787,6 +813,8 @@ case "$1" in
sync_routes) sync_routes ;;
bans) get_bans ;;
unban) unban_ip ;;
get_waf_rules) get_waf_rules ;;
toggle_waf_category) toggle_waf_category ;;
*) echo '{"error":"Unknown method"}' ;;
esac
;;

View File

@ -10,9 +10,14 @@
"action": { "type": "view", "path": "mitmproxy/status" },
"order": 1
},
"admin/secubox/security/mitmproxy/waf-filters": {
"title": "WAF Filters",
"action": { "type": "view", "path": "mitmproxy/waf-filters" },
"order": 2
},
"admin/secubox/security/mitmproxy/settings": {
"title": "Settings",
"action": { "type": "view", "path": "mitmproxy/settings" },
"order": 2
"order": 3
}
}

View File

@ -3,7 +3,7 @@
"description": "Grant access to mitmproxy",
"read": {
"ubus": {
"luci.mitmproxy": ["status", "settings", "alerts", "threat_stats", "subdomain_metrics", "bans"]
"luci.mitmproxy": ["status", "settings", "alerts", "threat_stats", "subdomain_metrics", "bans", "get_waf_rules"]
},
"uci": ["mitmproxy"]
},
@ -24,7 +24,8 @@
"haproxy_enable",
"haproxy_disable",
"sync_routes",
"unban"
"unban",
"toggle_waf_category"
]
},
"uci": ["mitmproxy"]