Sanitize val() to append to avoid XSS - javascript

Currently I'm using checkmarx to find vulnerabilities on mi code.
The javascript files aparently haev some potential xss vulnerabilites when I use jquery val() function and then try to append this val. How should I solve, sanitize or encode this to avoid this problem?
Here some examples about what checkmarx mark as vulnerability:
function insertContactToTable(table) {
var ContactId = jQuery("#select_contacts").val();
var ContactName = jQuery("#select_contacts option:selected").text();
var Type = jQuery("#select_contact_type").val();
if (ContactId != "" && Type != "") {
var ID = ContactId + "_" + Type;
var Img = "<img class='image pointer-item' src='/app/assets/img/icon-package/cross.png' alt='cross' onClick='removeTableLine(\"" + ID + "\")'/>";
if (jQuery("#" + table + " tbody tr:last").length > 0) {
jQuery("#" + table + " tbody tr:last").after("<tr id='" + ID + "' name='" + ID + "'><td id='" + ID + "' name='contact_list'>" + ContactName + "</td><td>" + Type + "</td><td>" + Img + "</td></tr>");
} else {
jQuery("#" + table + " tbody").html("<tr id='" + ID + "' name='" + ID + "'><td id='" + ID + "' name='contact_list'>" + ContactName + "</td><td>" + Type + "</td><td>" + Img + "</td></tr>");
}
}
...
It marks the following error:
The application's insertContactToTable embeds untrusted data in the generated output with after, at line 542 of app\assets\js\administration.js. This untrusted data is embedded straight into the output without proper sanitization or encoding, enabling an attacker to inject malicious code into the output.
The line 542 is the jQuery("#select_contacts").val(); but it happens the same with the others lines that use .val() and .text() function.
Also, on other functions happens the same while getting this .val() or .text() functions and trying to use them with append() or html() functions.
Finally, I also have same issue while getting ajax response and try to append it with append() o html().
Note: I'm using php on my project, sanitizing most of the variables with it.
Edit
I changed to DOM object as suggested in comments and the code now looks like this:
var ContactId = jQuery("#select_contacts").val();
var ContactName = jQuery("#select_contacts option:selected").text();
var Type = jQuery("#select_contact_type").val();
if (ContactId != "" && Type != "") {
var ID = ContactId + "_" + Type;
var Img = jQuery("<img>", { "class": 'image pointer-item', alt: 'cross', "src": '/app/assets/img/icon-package/cross.png'
}).on("click", function() {
removeTableLine(ID);
});
var row = $("<tr>", { id:"TR_" +ID , name: ID })
.append($("<td>", { id: ID, name: 'contact_list', text: ContactName }))
.append($("<td>", { text: Type }))
.append($("<td>").append(Img));
$("#" + table + " tbody").append(row);
}
but I still have the problem

Don't create a string of HTML, create a DOM object and set its attributes.
if (ContactId != "" && Type != "") {
var ID = ContactId + "_" + Type;
var Img = jQuery("<img>", {
"class": 'image pointer-item',
alt: 'cross'
}).click(function() {
removeTableLine(ID);
});
var row = $("<tr>", {
id: ID,
name: ID
})
.append($("<td>", {
id: ID,
name: 'contact_list',
text: ContactName
}))
.append($("<td>").append(Img))
$("#" + table + " tbody").append(row);
}
You don't need different code depending on whether there's already a last row or not. Just append the new row to the table body.
You have another problem, you're using the same ID for the <tr> and first <td> in the row. If you really need them both to have an ID, they should have different IDs.

Use the DOMPurify library to sanitize the val() and text() return values before .append-ing it to the DOM
var ContactId = DOMPurify.sanitize(jQuery("#select_contacts").val());
var ContactName = DOMPurify.sanitize(jQuery("#select_contacts option:selected").text());
var Type = DOMPurify.sanitize(jQuery("#select_contact_type").val());
if (ContactId != "" && Type != "") {
var ID = ContactId + "_" + Type;
var Img = jQuery("<img>", { "class": 'image pointer-item', alt: 'cross', "src": '/app/assets/img/icon-package/cross.png'
}).on("click", function() {
removeTableLine(ID);
});
var row = $("<tr>", { id:"TR_" +ID , name: ID })
.append($("<td>", { id: ID, name: 'contact_list', text: ContactName }))
.append($("<td>", { text: Type }))
.append($("<td>").append(Img));
$("#" + table + " tbody").append(row);
}
If there are attributes or tags you want to be allowed, you can pass a second parameter to the sanitize function to define that whitelist:
// allow only <b> and <q> with style attributes
var clean = DOMPurify.sanitize(dirty, {ALLOWED_TAGS: ['b', 'q'], ALLOWED_ATTR: ['style']});

Related

For each span data get id and check id from json response

I'm trying to check any id sending with ajax and response json getting the id from json then checking if there is an id into span and then add it but is not working is always adding and adding more and more
Jquery
e.results.forEach(function(e) {
var name = e.name;
var id = e.id;
if ($(".visitors span").length) {
$('.visitors span').each(function() {
var data_id = $(this).attr('data-id');
if (data_id != id) {
$(".visitors").append("<span data-id='" + id + "'>" + name + "</span>");
}
});
} else {
$(".visitors").append("<span data-id='" + id + "'>" + name + "</span>");
}
});
Although I think your code is correct, but a suggestion: Instead of looping through the spans you're appending, just check if a span with a data-id exists (using CSS Attribute-Equal Selector), if not append a new span like this:
e.results.forEach(function(e) {
var name = e.name;
var id = e.id;
var $span = $(".visitors span[data-id = '" + id + "']"); // select all the spans that have the data-id equal to id
if (!$span.length) { // if there is none
$(".visitors").append("<span data-id='" + id + "'>" + name + "</span>"); // then add a new one
}
});

Call custom function on one element at a time

I have a jQuery extension method to create custom animated drop-down select lists based on this answer. Using this method on a page with one drop-down works perfectly:
The extension method is as follows:
$.fn.extend({
slidingSelect: function (options) {
var select = $(this);
var selector = select.selector;
var width = $(selector).width();
var selectedValue = select.val();
if (selectedValue === "undefined")
selectedValue = select.find("option:first").val();
console.log($(selector + " option:selected").text());
var divToggle = $("<div class='SelectorToggle SelectorToggle-defualt'>" + $(selector + " option:selected").text() + "<button style='float: right; width: 20px' id='ddlImgBtn'></button></div>")
.attr({ id: select.attr("id") + "Toggle" })
.css({ width: select.width() + 20 })
.click(function () {
$(selector + "Toggle").toggleClass("SelectorToggle-defualt");
$(selector + "Toggle").toggleClass("SelectorToggle-pressed");
$(selector).slideToggle("fast");
}).insertBefore(select);
var optionCount = $(selector + " option").length;
if (optionCount < 5) {
select.attr("size", optionCount);
}
else {
select.attr("size", 5);
}
select.addClass("drop-down-selector");
$(selector).css({ 'width': select.width() + 20, 'position': 'absolute', "z-index": '9999' });
select.change(function () {
divToggle.html($(selector + " option:selected").text() + "<button style='float: right; width: 20px' id='ddlImgBtn'></button>");
$(selector + "Toggle").toggleClass("SelectorToggle-defualt");
$(selector + "Toggle").toggleClass("SelectorToggle-pressed");
$(selector).slideToggle("fast");
});
}
});
I call it as follows:
$("#LanguageSelector").hide().slidingSelect();
I am however having endless issues getting it to work on a page with multiple drop-downs. My dropdowns are dynamically created as part of a DataTable solution with server-side processing. The drop-downs in the footer:
If i call the following:
$("select").hide().slidingSelect();
then somehow all drop-downs on the page create the custom control:
if I attempt to call the extension method on each element individually:
$("select").hide().each(function(index) {
$(this).slidingSelect();
});
I also tried to call the extension method individually as the drop-downs are created (to just one of them):
$('#RelatedCasesGrid tfoot th').each(function () {
var col = $(this).html();
//..........
else if (col === "ComplaintTypeName") {
$(this).html(GetDropDownInput(col, caseId));
var element = $(this).find("select");
element.hide().slidingSelect();
}
The method GetDropDownInput(col, caseId) creates the drop-downs as follows:
function GetDropDownInput(col, id) {
var control;
$.ajax({
method: "GET",
dataType: "json",
async: false,
url: "/OATS/Api/GetColumnItems/" + id + "?column=" + col
}).done(function (data) {
control = "<select id='selector' class='table-filter-input-drop-down-list'><option value='' disabled selected>Filter by</option>"
for (var i = 0; i < data.length; i++) {
control += "<option col-type=" + data[i].Type + " value='" + data[i].Name + "'";
if (data[i].Selected) {
control += "selected='selected'";
}
control += ">" + data[i].Name + "</option>";
}
control += "</select>";
});
return control;
}
The result of this:
From: http://www.w3schools.com
The id attribute specifies a unique id for an HTML element (the value
must be unique within the HTML document).
But your ajax method create the same id for all selects: "selector". Change this method to create unique id (value of 'col' parameter seems be ok for this purpose), and then call:
$("#your_unique_id").hide().slidingSelect();

event.target.id.indexOf("foo") not working - Not working in IE

I have a JavaScript function that loops through classes and gets an ID which I have wrapped in a div called 'item'. Once they click on a button it bubbles up through the div which I have wrapped information in and collected the ID. For Example:
output = "<div id='item" + json_output[i].id + "'>" +
"<div class = 'itemBoxes'>"+
"<h3 class ='itemTitle'>" +json_output[i].classname + "</h3>" +
"<div class = 'paddingBottom'></div>" +
"<p class = 'itemDesc'>" + json_output[i].classdescription + '</p>' +
"<div class ='itemInfo'>" +
"<div class ='bookingItems'> <img src = 'img/glyphicons-268-credit-card.png'</img> <p class = 'itemDetails'>£" + json_output[i].classprice + "</p></div> "+
"<div class ='bookingItems'> <img src = 'img/glyphicons-46-calendar.png'</img> <p class = 'itemDetails'>" + json_output[i].classdate + "</p></div>" +
"<div class ='bookingItems'> <img src = 'img/glyphicons-55-clock.png'</img><p class = 'itemDetails'>"+ json_output[i].classstarttime +"</p></div>" +
"<div class ='bookingItems'> <img src = 'img/glyphicons-44-group.png'</img><p class = 'itemDetails'>" + json_output[i].classparticipants + " spaces </p></div>" +
"</div>" +
"<p id ='bookingBox'> <input type='button' class='bookingSubmit' value='Book Now'/> </p>" +
"</div>" +
"</div>";
target.innerHTML += output;
The code I use to find the ID is:
var fetchModifyButton;
//Gets the button that says 'Modify'
fetchModifyButton = _c("bookingSubmit");
//Remove Button.
for (var i = 0, j = fetchModifyButton.length; i < j; i++) {
fetchModifyButton[i].addEventListener("click", function () {
var e, productID, newID;
//Bubbles up and finds the ID of the product they want to modify
e = event.target;
while (e.id.indexOf('item') == -1) {
e = e.parentNode;
}
productID = e.id;
//Removes everything but the numbers.
newID = productID.replace(/[^0-9.]/g, "");
getClassInfoForBooking(newID, newID);
});
}
This works perfectly in Google Chrome, IE11, and most other browsers.
It doesn't work in IE8,9 or 10.
The error message I get in is:
SCRIPT5007: Unable to get property 'id' of undefinded or null reference
Then it points to the line: while (e.id.indexOf('item') == -1) {
I wondered if anyone had any ideas why?
use event.srcElement for IE
var addEvent = window.addEventListener||window.attachEvent;
fetchModifyButton[i].addEvent("click", function () {
var e, productID, newID;
//Bubbles up and finds the ID of the product they want to modify
e = event.target||event.srcElement;
while (e.id.indexOf('item') == -1) {
e = e.parentNode;
}
productID = e.id;
//Removes everything but the numbers.
newID = productID.replace(/[^0-9.]/g, "");
getClassInfoForBooking(newID, newID);
});

Hiding <p> field in javascript

Here's my code for gathering titles/posts from reddit's api:
$.getJSON("http://www.reddit.com/search.json?q=" + query + "&sort=" + val + "&t=" + time, function (data) {
var i = 0
$.each(data.data.children, function (i, item) {
var title = item.data.title
var url = item.data.url
var id = item.data.id
var subid = item.data.subreddit_id
var selftext = item.data.selftext
var selftextpost = '<p id="post' + i + '">' + selftext + '</p><br>'
var post = '<div>' + '' + title + '' + '</div>'
results.append(post)
results.append(selftextpost)
i++
});
});
Basically every post (selftext) is assigned a different paragraph id (post0, post1, post2, etc) for every result that's pulled. I'm also going to create a "hide" button that follows the same id scheme based on my i variable (submit0, submit1, submit2, etc). I want to write a function so that based on which button they click, it will hide the corresponding paragraph. I've tried doing an if statement that's like if("#hide" + i) is clicked, then hide the corresponding paragraph, but obviously that + i doesn't work. How else can I tackle this?
Could you try something like the below?
showhide = $("<a class='hider'>Show/Hide</a>");
results.append(showhide);
$(showhide).click(function() {
$(this).next().toggle();
}
Alternatively:
$.each(data.data.children, function (i, item) {
var title = item.data.title
var url = item.data.url
var id = item.data.id
var subid = item.data.subreddit_id
var selftext = item.data.selftext
var selftextpost = '<p id="post' + i + '">' + selftext + '</p><br>'
var showhide = $("<a class='hider" + i + "'>Show/Hide</a>");
var post = '<div>' + '' + title + '' + '</div>'
results.append(post)
results.append(selftextpost)
results.append(showhide);
$(showhide).click(function() {
$(this).next().toggle();
});
i++
});

How to append li using jQuery and using the id on the onclick method

Ok, below is my code:
for (var mycounter = currentcanvas.getObjects().length; mycounter > 0; mycounter--) {
var id = currentcanvas.getObjects().length - mycounter;
alert(id);
$("#frontlayers").prepend('<li id="' + id + '" class="layers"></span> Layer ' + (id + 1) + ': ' + " " + ' </li>');
$("#" + id).click(function(e) {
alert(id);
});
}​
This correctly adds the li with the text "Layer 1" and "Layer 2", but when I click on them the alert is always 2 instead of 0 and 1 accordingly.
does anyone know why this is happening? sorry I'm relatively new to jQuery.
This is a good use for $.each because using a handler function avoids the scope issue you have with the closure on the variable i:
$.each(currentcanvas.getObjects(), function(i, v) {
var id = i; // nb: numeric ID fields only allowed in HTML5
$('<li>', {
id: id,
'class': 'layers',
text: 'Layer ' + (id + 1) + ': '
}).appendTo('#frontlayers').on('click', function(e) {
alert(id);
});
});
That said, since your ID is stored on the clicked element anyway, you could have just used that directly - this.id

Categories