I'm learning xss prevention through this ppt:http://stash.github.io/empirejs-2014/#/2/23, and I have a question on this page.
It says "JavaScript sanitization doesn't save you from innerHTML", and I tried a simple test like this:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>test</title>
</head>
<body>
<div id="test"></div>
<script>
var userName = "Jeremy\x3Cscript\x3Ealert('boom')\x3C/script\x3E";
document.getElementById('test').innerHTML = "<span>"+userName+"</span>";
</script>
</body>
</html>
when I opened this html on my browser(chrome), I only saw the name "Jeremy",by using F12, I saw
<div id="test"><span>Jeremy<script>alert('boom')</script></span></div>
Although the script had been added to html, the alert box didn't come out.
"JavaScript sanitization doesn't save you from innerHTML" I think this means that the word "boom" should be alerted. Am I right?
According to MDN, innerHTML prevents <script> elements from executing directly1, which means your test should not alert anything. However, it does not prevent event handlers from firing later on, which makes the following possible:
var name = "\x3Cimg src=x onerror=alert(1)\x3E";
document.getElementById('test').innerHTML = name; // shows the alert
<div id="test"></div>
(script adapted from the example in the article, with escape sequences although I'm not sure those are relevant outside of <script> elements)
Since <script> elements never execute when inserted via innerHTML, it's not clear to me what that slide is trying to convey with that example.
1 This is actually specified in HTML5. MDN links to a 2008 draft; in the current W3C Recommendation, it's located near the end of section 4.11.1, just before section 4.11.1.1 begins:
Note: When inserted using the document.write() method, script elements execute (typically synchronously), but when inserted using innerHTML and outerHTML attributes, they do not execute at all.
Related
I've been playing around with web development and wanted to create a basic application which allows users to enter html into a text area, which is saved in local storage, then later inserted into a document element with .innerHTML.
Minimum working example:
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Prototyping</title>
</head>
<body>
<!--- Using bootstrap v. 5.2.0 --->
<form>
<label for="content"></label>
<textarea class="form-control" id="content"></textarea>
</form>
<div id="displayContent"></div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.2.0-beta1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2"
crossorigin="anonymous"></script>
<script src="index.js"></script>
</body>
</html>
JavaScript
const userInput = document.getElementById('content');
const displayInput = document.getElementById('displayContent')
userInput.addEventListener('input', (event) => {
localStorage.setItem(event.target.id, event.target.value);
displayInput.innerHTML = localStorage.getItem(event.target.id);
});
Now I was concerned that using .innerHTML would allow users to inject js code <script>alert('HAHA')</script>. However, scripts fail to run. Or at least with my limited knowledge of HTML, I cannot get a script to run. This is what I want, but I don't understand why. When inspecting the page, I will see the <script>. Is this because localStorage converts the input into strings? What is happening that prevents the script from running?
The reason why the alert you try to inject "fails to run", is because at this stage the DOM is already parsed and all the javascript within it is already executed. So, the code would not be executed again.
Still, since you are inserting HTML, any HTML that will be added, will also be rendered. And with that, there are also some ways to execute javascript-code like this. One example is the following snippet as an input:
<img src=z onerror="alert('Injected code')">
Similar results could be achieved with other event-listener-attributes or deferred scripts.
However, if you only save and open the input on the client-side and not expose it to other users, there is no way it could do any damage. It would be the same as if you use the console in the developer-menu that is built-in in every modern browser (F12 in most of them).
If that is still a problem for your use-case or you expose the inputs to other users, I would strongly recommend you to parse the text-input so that no js-code would be executed.
Probably the safest way of achieving this could be to only insert text instead of HTML:
displayInput.textContent = localStorage.getItem(event.target.id)
Another way could be could be to encode the < and > to their html equivilant (source):
let content = event.target.value.replace(/</g, "<").replace(/>/g, ">")
localStorage.setItem(event.target.id, content)
displayInput.innerHTML = localStorage.getItem(event.target.id)
I hope this helps. Keep it up!
I am a complete beginner to javascript. I am also new to this website. I am asking for help to complete an assignment. I have been trying for more than 4 hours by looking at lecture material and online for a solution. It is causing me a lot of unnecessary stress. Before javascript we only used CSS and Html. I was given 6 javascript tasks to manipulate the html file (taskc.html) already given to me.
The tasks are as follows
Make a statement to change contents of h1 from "Welcome" to "Text"
2nd statement should make an new alert window when the page loads that delivers a message explaining what the page is about
3rd statement should change the title to "text"
4th statement should log the contents (innerHTML) of the first paragraph element in the console.
5th statement should hide the contents of the second paragraph when the page loads
6th statement should change the contents of the header to have a new colour of your choice
Here is that html.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Task C - The Document Object Mode</title>
</head>
<body>
<h1 id="header">Welcome</h1>
<p id="first">This site uses JavaScript</p>
<p id="second">Javascript is very useful</p>
</body>
</html>
Because the actual coding im meant to add is meant to be in the .js file I was given. so I figured I had to link the js file in the html file so I added
<script type="text/javascript" src="taskc.js"></script>
With that out of the way I went to the lecture notes and I thought I would simply need to modify some of the code given to me there like
document.getElementById('demo').innerHTML = 'Hello World!';
When I put this code in brackets I got the error (document is not defined)
I modified it to match the requirements for task 1
here it is
document.getElementById('header').innerHTML = 'text';
I was confused because I didn't know what this error meant and of course Errors and how to fix them are never explained so I had to lookup how to resolve the error.
I found that to fix it I have to declare it as a variable so I ended up doing this.
var document = 'taskc.html';
When I did this for document, alert and console all the errors went away, but when I did a live preview only statement 1 was working
If anyone could help me fix this I would really appreciate because I don't understand enough javascript to be able to complete this in a reasonable amount of time.
So first: Please use Javascript functions to keep your code tidy and clean.
Example:
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Task C - The Document Object Mode</title>
</head>
<body>
<h1 id="header">Welcome</h1>
<p id="first">This site uses JavaScript</p>
<p id="second">Javascript is very useful</p>
<script type="text/javascript" src="taskc.js">test();</script>
</body>
</html>
function test(){
alert("This is a test!");
}
Always implement scripts that are document referenced at the bottom of your html.
If you use JQuery you can use following code to check document is loaded:
$(document).ready(function(){
//foo bar
});
I have a page with a javascript file at the end. the file is placed at the end so that I get access to all the dom elements.
let us say the markup looks like this
<html>
<head></head>
<body>
//lot of markup here
<script src="my-js.js"></script>
<body>
the sample markup is just to show the location of my js file.
the first like in the js file (my-js.js) is
document.body.style.visibility = 'hidden';
After the code runs I set the visibility back to hidden
From what I have understood(from a lot of articles related to this including in stackoverflow ones) is that the browser reaches the js, then executes it, and then continues with render and then paints.
If that was true, my code as described should work fine.
However, what is happening now is that, the page is shown (for less than 500ms) as it is before the code executed, then quickly hidden and then shown again after the code executed.
in short, what I want is:
page is hidden > code executes > page is shown
instead what I get is
page is shown > page is hidden > code executes > page is shown
My question is why is the page shown for that split second? what am I doing wrong here?
PS: Please note that I cannot change the location of the js nor add another. So, do not post any solution that suggest the same.
More importantly, I want to know why my code is wrong.
You might be interested in using the defer method.
defer means “wait for the parser to finish to execute this”. It’s roughly equivalent to binding your script to the DOMContentLoaded event, or using jQuery.ready. When the code does run, everything in the DOM will be available for you to use. Unlike async, defer’d code will run in the order it appears in the HTML of the page, it is just deferred until after the HTML is fully parsed.
For example:
<script src="my-js.js" defer></script>
See more here
Put the script tag right at the start of the body so it will be evaluated almost exactly as the body is rendered.
<html>
<head></head>
<body>
<script>
document.body.style.visibility = 'hidden';
</script>
<p>Sample text</p>
</body>
</html>
You can also add a style tag to set the body's visibility to hidden.
body{
visibility: hidden;
}
<html>
<head></head>
<body>
<p>Sample text</p>
</body>
</html>
I have no idea why this isn't working. I mean as far as I know It should print my array in alphabetical order to the div "output"
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title> Lexicographic ordering </title>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>
var words = [];
var input = prompt("Please enter a word or type end to stop prompts");
while (input != 'end') {
words.push(input);
input = prompt("Please enter a word or type end to stop prompts");
}
words.sort();
getElementById('#output').innerHTML= words.join();
</script>
</head>
<body>
<header>Lexicographic Ordering </header>
<hr>
<div class ="page-wrapper">
h1> Lexicographic Ordering </h1>
<div id="output"></div>
</div>
</body>
</html>
There are two small bugs in your code, and they're both in this line:
getElementById('#output').innerHTML= words.join();
getElementById is not a part of the window, it's a part of the document object, so you must reference it properly. Also, that method takes an ID, not a selector, so you don't need the # in front of it.
document.getElementById('output').innerHTML= words.join();
That should do what you want! Alternatively, since I notice you have jQuery included, you could do $('#output').innerHTML = ... to achieve the same effects.
You may also try to move the <script> block at the end, just before closing of the </body>. Anywhere after the <div id="output"></div>.
JavaScript on some browsers fails when they have to reference some elements which has not been parsed by their HTML parser when the script is executing or trying to reference them.
Also, you don't use # with getElementById(...);. # is used with Jquery. This is pure JavaScript. Make it getElementById('output').whatever...;
Edit:
Another option suggested by Patrick Evans is to move the JavaScript Code in an onload() event handler method to execute the code. This ensures that the HTML is fully loaded in the DOM before we try to manipulate it.
I am messing around with JavaScript experimenting to get a feel for it and have already hit a problem. Here is my html code:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
<link rel="stylesheet" type="text/css" href="styles.css">
<script type="text/javascript" src="testing.js"></script>
</head>
<body onload="writeLine()">
</body>
</html>
Here is the JavaScript testing.js:
function writeLine()
{
document.write("Hello World!")
}
Here is the style sheet styles.css:
html, body {
background-color: red;
}
So a very simple example, but I may have chose an awkward example, using on-load in a body tag. So the code above loads and runs the function, but the style sheet does nothing, unless I remove the script tags in the head. I have tried putting the script tags everywhere else, but nothing works. I have researched on-line how to properly link to JavaScript files, and have no found no clear solution, can anyone point out my error?
I have used JavaScript before, but I want a clear understanding from the beginning before I use it any longer
You cannot use document.write after the document is closed (which it will be when onload fires) without destroying the existing document (including links to stylesheets).
Instead, use DOM manipulation, which is covered by chapters 8 and 9 of the W3C JavaScript Core Skills.
Your problem is with the document.write() called in a wrong moment*. This method prints given text at current place in the page as was intended to work while the page still loads. Because you are calling it when the whole page was loaded, the results are unexpected (undefined?)
Instead you should manipulate the dom tree directly:
function writeLine() {
var text = document.createTextNode("Hello World!");
document.body.appendChild(text);
}
Actually in Opera browser I see red background for few milliseconds and then it goes back to white. Try commenting out document.write() - the background is as expected. Moreover you should include <script> tag at the end of body, but this won't solve your problem.
* to be honest, there is no good moment for calling document.write(), avoid it
In your particular example it doesn't matter where the script tag is added as the document.write command executes after the content is rendered, overwriting the existing content.
If you add an alert before overwriting the content you can see your page is red before it gets overwritten with Hello World.