Is this a bug within JavaScript? http://jsfiddle.net/SommerEngineering/mr8sZ/
<a href='javascript:test("test")'>Works</a><br/>
<a href='javascript:test("test"")'>Does not work</a>
Its looks like JS goes into the string, converts back the " into " and then tries to execute the command, which is then of course wrong.
You are correct. What you're writing there is html, so the html entity "e; is rendered as a double quote ", then executed as JavaScript. Because test("test""); is not valid javascript, this will throw an error. If you want to pass test" into the function, you would escape the quote like this: test("test\"");
Inline JavaScript is not a good practice and has tons of non-intuitive issues. Read some of these results: Why is inline JS bad?
Here's an example of how to do this properly.
var a = document.getElementById('myElem');
a.addEventListener('click', function() {
test('test"');
});
Just note there are many ways to get element references and you might want to use a class and attach the handler within a loop.
This is not a bug. The double quotes work because the HTML attribute has single quotes. However, the " entity is evaluated by HTML, so the data passed to the JavaScript engine is:
javascript:test("test"")
If you want to escape the quotes use
javascript:test("test\"")
as a \ escapes the quote.
This is not a js bug, indeed it's an html behavior. The " is an html entity that gets decoded to " prior to js execution.
Anyway, avoid to have embedded js in html, it's not a good practice, your case is one reason.
Related
THE SETUP:
On the page, in a hidden div, is a well-formed JSON object.
As part of this object, some of the values are HTML, and in this HTML, double-quotes are HTML-encoded, like so: "addtionalInfo": "If you need more help, please visit <a href="http://www.google.com">Google</a>"
Later on the page, I'm trying to write JS that will read this object in so other cool things can be done.
THE PROBLEM:
innerHTML seems to be implicitly decoding the quotes, which means JSON.parse() (and similar jQuery options) fail because the syntax bonks. I can't replace() the quotes since they're all over the place in proper JSONy ways.
AN EXAMPLE:
<span class="hiddenField" id="TheJSONObject">
{ "thing" : "thingvalue", "badthing" : "a <a href="http://www.google.com">link!</a>", "lastthing" : "lastthingvalue" }
</span>
<script>
var newobj = JSON.parse(document.getElementById("TheJSONObject").innerHTML.trim());
alert(newobj.thing);
PROOF FROM THE CONSOLE (CHROME):
console.log(document.getElementById("TheJSONObject").innerHTML)
{ "thing" : "thingvalue", "badthing" : "a <a href="http://www.google.com">link!</a>", "lastthing" : "lastthingvalue" }
THE QUESTION:
Is there any way to get the actual raw innerHTML without JS trying to do me a kindness like this so that JSON.parse() will work?
That’s completely impossible. You have a <span>, not a <script> or anything else that’s treated as literal text, so there’s no difference between a " and a ". You need to encode it properly to begin with; that probably means HTML-encoding the JSON-encoded object containing the HTML-encoded value for output as HTML.
If you’re not able to modify that output, the closest you can get will probably be to make a (XHR) request and parse it out manually with the entities intact.
When I allow users to insert data as an argument to the JS innerHTML function like this:
element.innerHTML = “User provided variable”;
I understood that in order to prevent XSS, I have to HTML encode, and then JS encode the user input because the user could insert something like this:
<img src=a onerror='alert();'>
Only HTML or only JS encoding would not help because the .innerHTML method as I understood decodes the input before inserting it into the page. With HTML+JS encoding, I noticed that the .innerHTML decodes only the JS, but the HTML encoding remains.
But I was able to achieve the same by double encoding into HTML.
My question is: Could somebody provide an example of why I should HTML encode and then JS encode, and not double encode in HTML when using the .innerHTML method?
Could somebody provide an example of why I should HTML encode and then
JS encode, and not double encode in HTML when using the .innerHTML
method?
Sure.
Assuming the "user provided data" is populated in your JavaScript by the server, then you will have to JS encode to get it there.
This following is pseudocode on the server-side end, but in JavaScript on the front end:
var userProdividedData = "<%=serverVariableSetByUser %>";
element.innerHTML = userProdividedData;
Like ASP.NET <%= %> outputs the server side variable without encoding. If the user is "good" and supplies the value foo then this results in the following JavaScript being rendered:
var userProdividedData = "foo";
element.innerHTML = userProdividedData;
So far no problems.
Now say a malicious user supplies the value "; alert("xss attack!");//. This would be rendered as:
var userProdividedData = ""; alert("xss attack!");//";
element.innerHTML = userProdividedData;
which would result in an XSS exploit where the code is actually executed in the first line of the above.
To prevent this, as you say you JS encode. The OWASP XSS prevention cheat sheet rule #3 says:
Except for alphanumeric characters, escape all characters less than
256 with the \xHH format to prevent switching out of the data value
into the script context or into another attribute.
So to secure against this your code would be
var userProdividedData = "<%=JsEncode(serverVariableSetByUser) %>";
element.innerHTML = userProdividedData;
where JsEncode encodes as per the OWASP recommendation.
This would prevent the above attack as it would now render as follows:
var userProdividedData = "\x22\x3b\x20alert\x28\x22xss\x20attack\x21\x22\x29\x3b\x2f\x2f";
element.innerHTML = userProdividedData;
Now you have secured your JavaScript variable assignment against XSS.
However, what if a malicious user supplied <img src="xx" onerror="alert('xss attack')" /> as the value? This would be fine for the variable assignment part as it would simply get converted into the hex entity equivalent like above.
However the line
element.innerHTML = userProdividedData;
would cause alert('xss attack') to be executed when the browser renders the inner HTML. This would be like a DOM Based XSS attack as it is using rendered JavaScript rather than HTML, however, as it passes though the server it is still classed as reflected or stored XSS depending on where the value is initially set.
This is why you would need to HTML encode too. This can be done via a function such as:
function escapeHTML (unsafe_str) {
return unsafe_str
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/\"/g, '"')
.replace(/\'/g, ''')
.replace(/\//g, '/')
}
making your code
element.innerHTML = escapeHTML(userProdividedData);
or could be done via JQuery's text() function.
Update regarding question in comments
I just have one more question: You mentioned that we must JS encode
because an attacker could enter "; alert("xss attack!");//. But if we
would use HTML encoding instead of JS encoding, wouldn't that also
HTML encode the " sign and make this attack impossible because we
would have: var userProdividedData =""; alert("xss attack!");//";
I'm taking your question to mean the following: Rather than JS encoding followed by HTML encoding, why don't we don't just HTML encode in the first place, and leave it at that?
Well because they could encode an attack such as <img src="xx" onerror="alert('xss attack')" /> all encoded using the \xHH format to insert their payload - this would achieve the desired HTML sequence of the attack without using any of the characters that HTML encoding would affect.
There are some other attacks too: If the attacker entered \ then they could force the browser to miss the closing quote (as \ is the escape character in JavaScript).
This would render as:
var userProdividedData = "\";
which would trigger a JavaScript error because it is not a properly terminated statement. This could cause a Denial of Service to the application if it is rendered in a prominent place.
Additionally say there were two pieces of user controlled data:
var userProdividedData = "<%=serverVariableSetByUser1 %>" + ' - ' + "<%=serverVariableSetByUser2 %>";
the user could then enter \ in the first and ;alert('xss');// in the second. This would change the string concatenation into one big assignment, followed by an XSS attack:
var userProdividedData = "\" + ' - ' + ";alert('xss');//";
Because of edge cases like these it is recommended to follow the OWASP guidelines as they are as close to bulletproof as you can get. You might think that adding \ to the list of HTML encoded values solves this, however there are other reasons to use JS followed by HTML when rendering content in this manner because this method also works for data in attribute values:
<a href="javascript:void(0)" onclick="myFunction('<%=JsEncode(serverVariableSetByUser) %>'); return false">
Despite whether it is single or double quoted:
<a href='javascript:void(0)' onclick='myFunction("<%=JsEncode(serverVariableSetByUser) %>"); return false'>
Or even unquoted:
<a href=javascript:void(0) onclick=myFunction("<%=JsEncode(serverVariableSetByUser) %>");return false;>
If you HTML encoded like mentioned in your comment an entity value:
onclick='var userProdividedData ="";"' (shortened version)
the code is actually run via the browser's HTML parser first, so userProdividedData would be
";;
instead of
";
so when you add it to the innerHTML call you would have XSS again. Note that <script> blocks are not processed via the browser's HTML parser, except for the closing </script> tag, but that's another story.
It is always wise to encode as late as possible such as shown above. Then if you need to output the value in anything other than a JavaScript context (e.g. an actual alert box does not render HTML, then it will still display correctly).
That is, with the above I can call
alert(serverVariableSetByUser);
just as easily as setting HTML
element.innerHTML = escapeHTML(userProdividedData);
In both cases it will be displayed correctly without certain characters from disrupting output or causing undesirable code execution.
A simple way to make sure the contents of your element is properly encoded (and will not be parsed as HTML) is to use textContent instead of innerHTML:
element.textContent = "User provided variable with <img src=a>";
Another option is to use innerHTML only after you have encoded (preferably on the server if you get the chance) the values you intend to use.
I have faced this issue in my ASP.NET Webforms application. The fix to this is relatively simple.
Install HtmlSanitizationLibrary from NuGet Package Manager and refer this in your application. At the code behind, please use the sanitizer class in the following way.
For example, if the current code looks something like this,
YourHtmlElement.InnerHtml = "Your HTML content" ;
Then, replace this with the following:
string unsafeHtml = "Your HTML content";
YourHtmlElement.InnerHtml = Sanitizer.GetSafeHtml(unsafeHtml);
This fix will remove the Veracode vulnerability and make sure that the string gets rendered as HTML. Encoding the string at code behind will render it as 'un-encoded string' rather than RAW HTML as it is encoded before the render begins.
I am trying to bind JavaScript event on page load in C# i have tried this code
Response.Write("<li><a href='#' onclick=BindID('" + SubMenu.ParentId + "','" + SubMenu.FormName + "','" + URL + "','" + SubMenu.FormCaption+ "')>" + newSubMenuItem.Text + "</a></li>");
after execution the following output is generated in my html page (on browser).
Copyrights Filing
the variable SubMenu.FormCaption contains string value 'Copyrights filing' but the browser is adding a double-quote when the variable contains a space, and the value becomes 'Copyrights" filing'.
What is the problem with the code?
That because the onclick have to look like:
onclick="BindID(...)"
and yours look like:
onclick=BindID(...)
so simply add quotes before and after
Response.Write("<li>" + newSubMenuItem.Text + "</li>");
so the broswer don't know how to parse it exactly then he guesses hopefully it will work
It's because of missing double quote at the beginning of the BindID method. The browser treats the double quote before url as ending tag of the li element hence gives the error.
It's always better to use string.format method to generate htmls dynamically. It's easy to maintain, read and understand.
like
String.Format("<li><a href='#' onclick="BindID('{0}','{1}','{2}','{3}')>{4}</a></li>", SubMenu.ParentId, SubMenu.FormName, SubMenu.FormCaption,newSubMenuItem.Text);
Got me stumped. I don't have a clue why this is happening.
My answer is more of an alternative approach for you:
var markup = String.Format("<li><a href='#' onclick=BindID('{0}','{1}','{2}','{3}')>{4}</a></li>", SubMenu.ParentId, SubMenu.FormName, SubMenu.FormCaption,newSubMenuItem.Text);
Response.Write(markup);
I'd recommend this anyway depending on the context of your problem (can improve performance).
http://msdn.microsoft.com/en-us/library/system.string.format(v=vs.110).aspx
On page load you can only paste this code. When page will load JavaScript code will run. Change the function name to your own function .
ScriptManager.RegisterStartupScript(Page, Page.GetType(), Guid.NewGuid().ToString(), `"javascript:funclass();", true);`
You are being led up the garden path here by using a browser's inspect element function, in this case Chrome's I suspect, which is giving the browser's best interpretation of the malformed html. In cases like this you should always use View Source to see the raw output. If you do this you'll see that what's output is in fact:
<li><a href='#' onclick=BindID('59','Registration','ApplicationForms/CaseManagment/Case.aspx','Copyrights filing')>Copyrights Filing</a></li>
looking at this, and to be fair on Inspect Element - it probably does help to compare the two, you should be able to spot, as other have pointed out, that onclick attribute's value is not being wrapped in quotes as it needs to be.
The quote mark you see in the middle of 'Copyrights" filing' in the Inspect Element view is the result of the browser terminating the onclick value at the first white space, then wrapping it all up in quotes itself.
Perhaps this is expected, but I found it odd since I am now starting with jQuery.
So, I am writing an application using node and jade. In the index.jade I have a statement of the form
p Welcome subscriber
span(id="subscriber") someID
Now once the connection is established between the client and the server, the server sends a welcome JSON message with some data. One of them is the id of the client which I want to replace above. Once the client receives the welcome JSON message it initializes the appropriate structures and then I make a call to a function loadStats:
function loadStats() {
var myText = "" + myData.id + ".";
$('#subscriber').text(myText);
$('#subscriber').html(myText);
};
In the screen I can see that the text "someID" is replaced by the ID of the client. However, when I actually inspect the html code of the page that I am looking at I see a statement of the form:
<p>Welcome subscriber <span id="subscriber">someID</span></p>
In other words in the actual HTML code the text "someID" has not been replaced. Is this something expected? How was the replacement done? Moreover, it appears that working with either of the statements
$('#subscriber').text(myText);
$('#subscriber').html(myText);
gives the replication on the screen but not on the actual html content of what is presented on screen. Is this the correct behavior? From what I understood (and expect) the .text() replaces the visual data of the element with the specific id and the .html() replaces the content. Am I missing something?
Thanks in advance. jQuery rookie here.
Two rules for expressions in pug:
In attributes you use quotes to output literal text and you leave the quotes out when you want to use a variable, and
For the content of a tag you use an equals sign when you want pug to evaluate an expression, or don't put anything if you want literal text
So with those rules in mind, looking at your code you will output the attribute "subscriber" as a literal and "someId" as a literal.
span(id="subscriber") someID
Results in:
<span id="subscriber">someId</span>
You wanted both to be dynamic so remove the quotes in the attribute and put an equals sign after the element:
span(id= subscriber)= someID
This will dynamically replace both with variables.
I have in my views some code as this
$(".someclass").hover(function(){
$(this).append("#{render "layouts/show_some_file", title: "some_file"}");
});
The show_some_file.html.haml file consists of two nested basic divs
In my browser, I get
$(".someclass").hover(function(){
$(this).append("<div>
<div>some text</div>
</div>
");
});
On hover, I get in my chrome console SyntaxError: Unexpected token ILLEGAL. I deleted my white spaces in my console, and it worked. But how to clean the white spaces in my ruby rendering ?
I am not entirely certain it will help, but you probably should use the "<%= render ... %>" variant rather than the #{}
And since it's for javascript, the correct way would be "<%= escape_javascript(render ...) %>"
If using HAML, substitute the ERB for however the markup is written there.
Edit: might be
!= "$(this).append("#{escape_javascript(render "layouts/show_some_file", title: "some_file")}");"
Since the result of your {#render} is HTML, and although you might use it once, it might make more sense to store it in HTML, and retrieve it with JavaScript. Mimicking templating, here's an example of what I mean:
<script id="my_render" type="text/template">
#{render "layouts/show_some_file", title: "some_file"}
</script>
<script type="text/javascript">
$(document).ready(function () {
var render_content = $("#my_render").html();
$(".someclass").hover(function () {
$(this).append(render_content);
});
});
</script>
It kind of acts like a template. You use a script tag, but you set its type to something that doesn't cause it to be executed. Since script tags are never visible on a page, you would never have visual problems...unlike doing this inside of a div...the HTML is then "separate" from the rest of the page.
I'm sure there's a better solution using Ruby, but if you're outputting a partial view to JavaScript code, I'd have to ask why. It makes more sense to me to put in a "template". I understand this doesn't directly answer your immediate question, but it's an alternative :)
In fact, I got it, one of the right thing to do is :
$("someclass").hover(function(){
$(this).append("#{escape_javascript render "layouts/show_some_file", title: "some title"}");
});
The obvious thing to do is edit layouts/show_some_file & remove white space. It's not really whitespace that's the problem, but carriage returns. Javascript doesn't like multi-line strings. If I knew Ruby, I could probably write a regex that gets rid off stuff like "\r\n", which is carriage return line feed in PHP/C syntax.