feat: Add CSRF tokens to all JavaScript fetch calls and fix XSS
Security improvements across all JavaScript files: CSRF Protection: - assets/js/ticket.js - Added X-CSRF-Token header to 5 fetch calls (update_ticket.php x3, add_comment.php, assign_ticket.php) - assets/js/dashboard.js - Added X-CSRF-Token to 8 fetch calls (update_ticket.php x2, bulk_operation.php x6) - assets/js/settings.js - Added X-CSRF-Token to user preferences save - assets/js/advanced-search.js - Added X-CSRF-Token to filter save/delete XSS Prevention: - assets/js/ticket.js:183-209 - Replaced insertAdjacentHTML() with safe DOM API (createElement/textContent) to prevent script injection in comment rendering. User-supplied data (user_name, created_at) now auto-escaped via textContent. All state-changing operations now include CSRF token validation. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -33,7 +33,8 @@ function saveTicket() {
|
||||
fetch(apiUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-Token': window.CSRF_TOKEN
|
||||
},
|
||||
body: JSON.stringify({
|
||||
ticket_id: ticketId,
|
||||
@@ -140,7 +141,8 @@ function addComment() {
|
||||
fetch('/api/add_comment.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-Token': window.CSRF_TOKEN
|
||||
},
|
||||
body: JSON.stringify({
|
||||
ticket_id: ticketId,
|
||||
@@ -178,18 +180,33 @@ function addComment() {
|
||||
.replace(/\n/g, '<br>');
|
||||
}
|
||||
|
||||
// Add new comment to the list
|
||||
// Add new comment to the list (using safe DOM API to prevent XSS)
|
||||
const commentsList = document.querySelector('.comments-list');
|
||||
const newComment = `
|
||||
<div class="comment">
|
||||
<div class="comment-header">
|
||||
<span class="comment-user">${data.user_name}</span>
|
||||
<span class="comment-date">${data.created_at}</span>
|
||||
</div>
|
||||
<div class="comment-text">${displayText}</div>
|
||||
</div>
|
||||
`;
|
||||
commentsList.insertAdjacentHTML('afterbegin', newComment);
|
||||
|
||||
const commentDiv = document.createElement('div');
|
||||
commentDiv.className = 'comment';
|
||||
|
||||
const headerDiv = document.createElement('div');
|
||||
headerDiv.className = 'comment-header';
|
||||
|
||||
const userSpan = document.createElement('span');
|
||||
userSpan.className = 'comment-user';
|
||||
userSpan.textContent = data.user_name; // Safe - auto-escapes
|
||||
|
||||
const dateSpan = document.createElement('span');
|
||||
dateSpan.className = 'comment-date';
|
||||
dateSpan.textContent = data.created_at; // Safe - auto-escapes
|
||||
|
||||
const textDiv = document.createElement('div');
|
||||
textDiv.className = 'comment-text';
|
||||
textDiv.innerHTML = displayText; // displayText already sanitized above
|
||||
|
||||
headerDiv.appendChild(userSpan);
|
||||
headerDiv.appendChild(dateSpan);
|
||||
commentDiv.appendChild(headerDiv);
|
||||
commentDiv.appendChild(textDiv);
|
||||
|
||||
commentsList.insertBefore(commentDiv, commentsList.firstChild);
|
||||
} else {
|
||||
console.error('Error adding comment:', data.error || 'Unknown error');
|
||||
}
|
||||
@@ -283,7 +300,10 @@ function handleAssignmentChange() {
|
||||
|
||||
fetch('/api/assign_ticket.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-Token': window.CSRF_TOKEN
|
||||
},
|
||||
body: JSON.stringify({ ticket_id: ticketId, assigned_to: assignedTo })
|
||||
})
|
||||
.then(response => response.json())
|
||||
@@ -316,7 +336,10 @@ function handleMetadataChanges() {
|
||||
|
||||
fetch('/api/update_ticket.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-Token': window.CSRF_TOKEN
|
||||
},
|
||||
body: JSON.stringify({
|
||||
ticket_id: ticketId,
|
||||
[fieldName]: fieldName === 'priority' ? parseInt(newValue) : newValue
|
||||
@@ -418,7 +441,8 @@ function updateTicketStatus() {
|
||||
fetch('/api/update_ticket.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-Token': window.CSRF_TOKEN
|
||||
},
|
||||
body: JSON.stringify({
|
||||
ticket_id: ticketId,
|
||||
|
||||
Reference in New Issue
Block a user