Harden CSP by removing unsafe-inline for scripts

Refactored all inline event handlers (onclick, onchange, onsubmit) to use
addEventListener with data-action attributes and event delegation pattern.

Changes:
- views/*.php: Replaced inline handlers with data-action attributes
- views/admin/*.php: Same refactoring for all admin views
- assets/js/dashboard.js: Added event delegation for bulk/quick action modals
- assets/js/ticket.js: Added event delegation for dynamic elements
- assets/js/markdown.js: Refactored toolbar button handlers
- assets/js/keyboard-shortcuts.js: Refactored modal close button
- SecurityHeadersMiddleware.php: Enabled strict CSP with nonces

The CSP now uses script-src 'self' 'nonce-{nonce}' instead of 'unsafe-inline',
significantly improving XSS protection.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-30 13:15:55 -05:00
parent 37be81b3e2
commit c3f7593f3c
13 changed files with 564 additions and 158 deletions

View File

@@ -73,7 +73,7 @@ $nonce = SecurityHeadersMiddleware::getNonce();
<div style="display: flex; gap: 0.5rem; align-items: center;">
<input type="text" id="newKeyValue" readonly
style="flex: 1; padding: 0.75rem; font-family: var(--font-mono); font-size: 0.85rem; background: var(--bg-primary); border: 2px solid var(--terminal-green); color: var(--terminal-green);">
<button onclick="copyApiKey()" class="btn" title="Copy to clipboard">Copy</button>
<button data-action="copy-api-key" class="btn" title="Copy to clipboard">Copy</button>
</div>
</div>
@@ -135,7 +135,7 @@ $nonce = SecurityHeadersMiddleware::getNonce();
</td>
<td>
<?php if ($key['is_active']): ?>
<button onclick="revokeKey(<?php echo $key['api_key_id']; ?>)" class="btn btn-secondary" style="padding: 0.25rem 0.5rem; font-size: 0.8rem;">
<button data-action="revoke-key" data-id="<?php echo $key['api_key_id']; ?>" class="btn btn-secondary" style="padding: 0.25rem 0.5rem; font-size: 0.8rem;">
Revoke
</button>
<?php else: ?>
@@ -162,6 +162,22 @@ $nonce = SecurityHeadersMiddleware::getNonce();
</div>
<script nonce="<?php echo $nonce; ?>">
// Event delegation for data-action handlers
document.addEventListener('click', function(event) {
const target = event.target.closest('[data-action]');
if (!target) return;
const action = target.dataset.action;
switch (action) {
case 'copy-api-key':
copyApiKey();
break;
case 'revoke-key':
revokeKey(target.dataset.id);
break;
}
});
document.getElementById('generateKeyForm').addEventListener('submit', async function(e) {
e.preventDefault();