I am trying to make a to-do application in pure HTML5 and Javascript and I have come across the problem of sanitizing the input.
For eg: If user enters <script>alert("XSS")</script>, the code is executed on the page.
Code for adding an element is:
if ($('#TextArea').val() !== "") {
var taskID = new Date().getTime();
var taskMessage = $('#textArea').val();
localStorage.setItem(taskID, taskMessage);
}
while the code for displaying the elements is:
var i = 0;
for (i = localStorage.length; i != 0; i--) {
var taskID = localStorage.key(i - 1);
$('#task').append("<li id='" + taskID + "'>" + localStorage.getItem(taskID) + "</li>");
}
Is there any way to sanitize the data using only HTML5 and Javascript properties?
As with any and all XSS prevention: Don't build HTML from strings, especially not when those strings contain user-supplied values.
jQuery has a convenient facility to build elements safely - you can pass in an object with properties:
$("<li>", {
id: taskID,
text: localStorage.getItem(taskID)
}).appendTo('#task');
In fact, I recommend that you absolutely never use string concatenation to build HTML. For more complex situations than the above, use a well-tested HTML templating library like Mustache or Handlebars.
Related
I need to create a javacript function that downloads the html source code of a web page and returns the number of times a CSS class is mentioned.
var str = document.body.innerHTML;
function getFrequency(str) {
var freq = {};
for (var i=0; i<string.length;i++) {
var css_class = "ENTER CLASS HERE";
if (freq[css_class]) {
freq[css_class]++;
} else {
freq[css_class] = 1;
}
}
return freq;
};
What am I doing wrong here?
What am I doing wrong here?
I hate to say it, but fundamentally... everything. Getting information about HTML does not involve string functions or regular expressions. HTML cannot be dealt with this way, its rules are way too complex.
HTML needs to be parsed by an HTML parser.
In the browser there are two possible scenarios:
If you work with the current document (as you seem to do), then the parsing is already done by the browser.
Counting the number of times a CSS class is used actually is the same thing as finding out how many HTML elements have that class. And that is easily done via document.querySelectorAll() and a CSS selector.
var elements = document.querySelectorAll(".my-css-class");
alert("There are " + elements.length + " occurrences of the class.");
If you have an HTML string that you loaded from somewhere, you need to parse it first. In JavaScript you can make the browser parse the HTML for you very easily:
var html = '<div class="my-css-class">some random HTML</div>';
var div = document.createElement("div");
div.innerHTML = html; // parsing happens here
Now you can employ the same strategy as above, only with div as your selector context:
var elements = div.querySelectorAll(".my-css-class");
alert("There are " + elements.length + " occurrences of the class.");
I'm building a website that will have a JS multi-dimensional array in a .js file in the scripts folder on the server. In the array will be video embed codes (Vimeo iframes) and additional strings for composers, players and piece names. There will about 1000 videos in the array.
var videos = [ ['embed code', 'composer name', 'player name', 'piece name'], ['embed code', 'composer name', 'player name', 'piece name']...];
There will be a search text box for users to do specific searches by composer, player, etc. A jQuery script will iterate through each inner array to find matches to the user's query and present them on the page. It will look basically like this:
function getArray(video) {
if (campyear === video[j]) {
var pos = video.indexOf(video[j]);
$('#searcharea').append('<td>' + video[(pos - pos)] + '</td><td><h3>Composer: ' + video[(pos -pos) + 1] + '</h3><br><h3>Player: ' + video[(pos - pos) + 2] + '</h3><br><h3>Piece: ' + video[(pos - pos) + 3] + '</h3></td>');
}
else
noResultCount++;
if (campyear === video[j] && count % 2 === 0)
$('#searcharea').append('</tr><tr>');
if (campyear === video[j])
count++;
if (i === videos.lenght && j === 4)
$('#searcharea').append('</table>');
if (noResultCount === videos.length * 5)
$('#searcharea').html("<h4>No results found for " + yearvalue + " " + buttonvalue + ". Not all camps have videos for every year.</h4>");
$('#searcharea').fadeIn(500);
} // End of getArray()
...
...
...
for (i = 0; i < videos.length; i++) {
for (j = 0; j < 5; j++) {
getArray(videos[i]);
}
}
I know there are security issues with the traditional SQL databases and PHP that need to be considered, but in this case should I be concerned about any threats to the data or website? My thought was the script can only read the data and print it so there wasn't much someone could do, but I'm not sure. The data isn't sensitive.
Thanks for your time.
The issue is that if someone can alter the file before it gets read in, they can inject any JavaScript code into it. One way to alter the file would be to hack your server, but they could also do it by taking over proxies that don't have to touch your machine at all. They they would have to somehow trick clients into going through the proxy, but you can't stop that from happening.
The easiest fix for this is to use a JSON file instead of a JavaScript file. JSON's syntax is very close to the syntax used for JS literals: as far as I can see from your example, the only changes you'd need to make to the file are to get rid of the "var videos =" at the start and swap your single-quotes for double-quotes. In code, exchange whatever works to this effect:
// Assume that getJS() grabs your JavaScript file
// and returns a String with the text of that file.
var videoCode = getJS();
eval(videoCode);
...for something that works like this:
// Assume that getJSONData() grabs your JSON
// and returns a String with the text of the file.
jsonData = getJSONData();
var videos = JSON.parse(jsonData);
Note that we're using JSON.parse (which has polyfills for old browsers) instead of eval. We do this because that puts the code through a dedicated JSON parser instead of a JavaScript one. JSON doesn't know how to deal with code, so even if an attacker tries to inject code by changing the file, the changed code won't work, because JSON won't know what to do with it. Obviously you don't want your app to just stop in the middle, but it's better than letting the attacker take over.
I am querying my DB with some query which returns 2 fields. I'm just wondering what's the better/best way of displaying the search results.
in the old days, I would have been using string concatenation.
example:
var html="";
$.each(data, function () {
var html = html + "<div><span>" + this.field1 + "</span><br /><span>" + this.field2 + "</span><br /></div>";
});
I'm hoping things would've have improved and something better like jquery can be used? I did search the net but can't find anything useful.
Thanks a lot.
String concatenation is still quite popular. But with jQuery you can create elements using object syntax:
$.each(data, function() {
var field1 = $("<span>", { text: this.field1 });
var field2 = $("<span>", { text: this.field2 });
$("<div>").append(field1, "<br>", field2).appendTo("#results");
});
However, it's quite possible that this will be slower than the concatenation version. This makes lots of calls to DOM functions to create elements and append them to the DOM, one at a time. String concatenation, on the other hand, is relatively efficient. If you do all the concatenation, and then finally do $("#results").html(html) at the end, it will make use of the browser's internal HTML parser to construct all the elements in one fell swoop. This is optimized very heavily in all browsers.
You could use the append function in JQuery.
$(document).ready(function () {
var div = $("<div></div>");
var span1 = $("<span></span>");
span1.append("value 1");
var span2 = $("<span></span>");
span2.append("value 2");
div.append(span1).append("<br>").append(span2).append("<br>");
$("body").append(div);
});
Replace the text values with the values you are returning from your query.
See my JSFiddle
I have a program which involves taking some user imputed values on a web page. These values are then sent out via a serial port to some control electronics.
There are six different "zones" and these have 6 values associated with each of them which are all set on the page by the user and read and stored by javascript.
I had been using 6 arrays to store the data but I would like to now use objects as I think this will make the code more readable when I refer to and manipulate the data elsewhere on the page.
This gives me 6 objects with 6 properties each, so I have for example zone1.duration - zone1.repeat .... zone6.op
So is this a good and efficient way to store the values? Also I do need to harvest the data from the web page to start with and interpret it for other functions associated with the web page. Before I did this in a simple loop cycling through the different zones and I am not sure how to do this with the objects.
The code below illustrates what I would like to do to get the values loaded from the web page, the document.getElementById part does work as I used that before but I don't know the proper syntax to cycle through the different zones and assign the properties. I have shown my poor attempt on the first line only.
for (i = 1; i < 7; i++){
('zone'+ i )["op"] = document.getElementById('Z' + i + 'Operate').value;
zone1["onHour"] = document.getElementById('Z' + i + 'OnTimeH').value;
zone1["onMinute"] = document.getElementById('Z' + i + 'OnTimeM').value;
zone1["duration"] = document.getElementById('Z' + i + 'Duration').value;
zone1["repeat"] = document.getElementById('Z' + i + 'Repeat').value;
zone1["ex"] = document.getElementById('Z' + i + 'Extra').value;
}
Hopefully this provides an idea of what I am trying to achieve. My questions are: Is this a good way to do it in the first place and if so what to I need to alter to get the above code to work. If not what would be a better way?
Thanks for looking.
I think you're looking for an array of objects. For example:
var zones = [,{},{},{},{},{},{}]; // leading comma indicates element 0 not used.
for (i = 1; i < 7; i++){
zones[i].op = document.getElementById('Z' + i + 'Operate').value;
zones[i].onHour = document.getElementById('Z' + i + 'OnTimeH').value;
// etc
}
I have a small block I wanted to convert to using jQuery for a couple of different purposes, but mainly to reverse engineer how it works to imporve my jQuery skills. I tried taking a go at it, but could not figure out all of the conversions.
The following Javascript block iterated through the checkboxes rendered in an ASP.NET TreeView control client-side and scan for checkboxes with a className=disabledTreeviewNode (this equivilent functionality cannot be achieved purely server side).
function DisableCheckBoxes(treeviewClientID) {
var treeView = document.getElementById(treeviewClientID);
if (treeView) {
//Get all the checkboxes which are 'inputs' in the treeview
var childCheckBoxes = treeView.getElementsByTagName("input");
//Iterate through the checkboxes and disable any checkbox that has a className="disabledTreeviewNode"
for (var i = 0; i < childCheckBoxes.length; i++) {
var textSpan = childCheckBoxes[i].parentNode.getElementsByTagName("span")[0];
if (textSpan != null && textSpan.firstChild)
if (textSpan.className == "disabledTreeviewNode" || textSpan.firstChild.className == "disabledTreeviewNode")
childCheckBoxes[i].disabled = true;
}
}
}
I tried changing the following:
var treeView = document.getElementById(treeviewClientID);
to
var treeView = $('#' + treeviewClientID);
However then I could no longer call getElementsByTagName. I tried to use the jQuery equivilent of .find but then the code started to behave differently and I was a bit lost.
Can anyone assist on converting this small block to use jQuery? Comments are welcome as to if this is worthwhile or even if there is a better way.
EDIT: This class=disabledTreeviewNode is assigned server-side like this:
tn.Text = "<span class=disabledTreeviewNode>" + tn.Text + "</span>";
It's a bit of a hack/flag so that client-side code can read it and set it's parent which is the checkbox to disabled. Why the Parent? I can't directly set the class on the checkbox in code because that property is not accessible. The hack: set the TreeView object's .Text to have the <span class=disabledTreeviewNode> value and then set it's parent (the checkbox) to disabled client-side.
Many of the jQuery object's methods call .each() method behind the scene, so you don't have to iterate through the collection, jQuery does this for you.
$('#' + treeviewClientID + ' input').filter(function() {
return $(this.parentNode).find('.disabledTreeviewNode').length;
}).prop('disabled', true);
$('#' + treeviewClientID + ' span:has(.disabledTreeviewNode) input')
.prop('disabled', true);