I'm wanting to capture my search terms and pass them to a JavaScript variable, but I don't know how to handle quotes that might come through.
Here's what I have currently:
var searchTerms = "<!--#echo var="terms"-->";
var pattern = / /g;
newSearchTerms = searchTerms.replace(/[^a-zA-Z 0-9]+/g,'');
var searchStr=newSearchTerms.replace(pattern,"_");
I'm concerned that should "terms" contain double quotes (or an apostrophy if I use single quotes in the JS) then my function will fail.
How do I escape the string before it gets into script?
Thanks,
Steve
Edit/answer: I ended up doing this by moving this to an external script that captured and parsed the querystring rather than echoing it in the HTML.
If terms contains quotation marks, by the time you have done var searchTerms = "<!--#echo var="terms"-->"; it is already too late to replace any quotation marks, your JavaScript will be invalid. For example, if terms contains These are the "terms" your JavaScript would appear as follows (and produce a syntax error in the browser):
var searchTerms = "These are the "terms"";
If you are sure terms only contains double-quotes, you could do:
var searchTerms = '<!--#echo var="terms"-->';
If it could contain both single-quotes and double-quotes, you need to sanitize the output on the server using a server-side technology more sophisticated than <!--#echo var="..."-->.
From your code it looks like you're using Apache SSI includes. The echo SSI has an attribute called encoding which wil let you specify url-style encoding. You can encode quotes this way and simply unencode in Javascript with unescape()
Try this:
var terms = "<!--#echo encoding="url" var="terms"-->";
terms = unescape(terms)
i would add a javascript to the onchange event for the search textbox. capture the keystroke and ignore the quotes and any other special characters that might be entered. if the input is coming from the server side, then sanitize it before sending it to your script.
Related
I need to read dot ner reesources string in java script as mention below.
var resources = #Html.ResourceStrings("Home_General_", Resources.ResourceManager);
The above line will render all the resources (from Dot net resource file) which start with resource key as "Home_General_"
Some of the values from the resources are like "Hi "XYZ" are you there" i.e The string contains quotes character.
If the string has quotes the above call fails.
The one way to avoid this problem is escape the special character as "Hi \"XYZ\" are you there"
Any other way where we can avoid this, As I don't want to pollute my resource string with lot of escape (\) characters.
You need to Javascript-escape any string when you render it as a Javascript string literal.
You must also remove the outer quotes from the string resource; that should be text, not a half-valid Javascript expression.
Use code like this to retrieve a single resource string:
var resourceXYZ = '#Html.Raw(HttpUtility.JavaScriptStringEncode(Resources.ResourceManager.GetString("Home_General_XYZ")))';
We do the following:
We get the resource string via Resources.ResourceManager.GetString().
We pass the result to HttpUtility.JavaScriptStringEncode to escape any special characters in JavaScript.
We pass the result to Html.Raw() to prevent Razor from applying HTML encoding on this string.
We then output the text enclosed in single quote quaracters into the page.
The function Html.ResourceStrings is not a standard function that is part of MVC. Someone at your place must have written it. If you show us this code, we could tell you how to rewrite it to return valid JavaScript literals.
You could wrap your #Html.ResourcesString(...) with HttpUtility.JavaScriptStringEncode which will handle all escape issues.
var resources = #HttpUtility.JavaScriptStringEncode(Html.ResourceStrings("Home_General_", Resources.ResourceManager));
I would like to store a JSON's contents in a HTML document's source, inside a script tag.
The content of that JSON does depend on user submitted input, thus great care is needed to sanitise that string for XSS.
I've read two concept here on SO.
1. Replace all occurrences of the </script tag into <\/script, or replace all </ into <\/ server side.
Code wise it looks like the following (using Python and jinja2 for the example):
// view
data = {
'test': 'asdas</script><b>as\'da</b><b>as"da</b>',
}
context_dict = {
'data_json': json.dumps(data, ensure_ascii=False).replace('</script', r'<\/script'),
}
// template
<script>
var data_json = {{ data_json | safe }};
</script>
// js
access it simply as window.data_json object
2. Encode the data as a HTML entity encoded JSON string, and unescape + parse it in client side. Unescape is from this answer: https://stackoverflow.com/a/34064434/518169
// view
context_dict = {
'data_json': json.dumps(data, ensure_ascii=False),
}
// template
<script>
var data_json = '{{ data_json }}'; // encoded into HTML entities, like < > &
</script>
// js
function htmlDecode(input) {
var doc = new DOMParser().parseFromString(input, "text/html");
return doc.documentElement.textContent;
}
var decoded = htmlDecode(window.data_json);
var data_json = JSON.parse(decoded);
This method doesn't work because \" in a script source becames " in a JS variable. Also, it creates a much bigger HTML document and also is not really human readable, so I'd go with the first one if it doesn't mean a huge security risk.
Is there any security risk in using the first version? Is it enough to sanitise a JSON encoded string with .replace('</script', r'<\/script')?
Reference on SO:
Best way to store JSON in an HTML attribute?
Why split the <script> tag when writing it with document.write()?
Script tag in JavaScript string
Sanitize <script> element contents
Escape </ in script tag contents
Some great external resources about this issue:
Flask's tojson filter's implementation source
Rail's json_escape method's help and source
A 5 year long discussion in Django ticket and proposed code
Here's how I dealt with the relatively minor part of this issue, the encoding problem with storing JSON in a script element. The short answer is you have to escape either < or / as together they terminate the script element -- even inside a JSON string literal. You can't HTML-encode entities for a script element. You could JavaScript-backslash-escape the slash. I preferred to JavaScript-hex-escape the less-than angle-bracket as \u003C.
.replace('<', r'\u003C')
I ran into this problem trying to pass the json from oembed results. Some of them contain script close tags (without mentioning Twitter by name).
json_for_script = json.dumps(data).replace('<', r'\u003C');
This turns data = {'test': 'foo </script> bar'}; into
'{"test": "foo \\u003C/script> bar"}'
which is valid JSON that won't terminate a script element.
I got the idea from this little gem inside the Jinja template engine. It's what's run when you use the {{data|tojson}} filter.
def htmlsafe_json_dumps(obj, dumper=None, **kwargs):
"""Works exactly like :func:`dumps` but is safe for use in ``<script>``
tags. It accepts the same arguments and returns a JSON string. Note that
this is available in templates through the ``|tojson`` filter which will
also mark the result as safe. Due to how this function escapes certain
characters this is safe even if used outside of ``<script>`` tags.
The following characters are escaped in strings:
- ``<``
- ``>``
- ``&``
- ``'``
This makes it safe to embed such strings in any place in HTML with the
notable exception of double quoted attributes. In that case single
quote your attributes or HTML escape it in addition.
"""
if dumper is None:
dumper = json.dumps
rv = dumper(obj, **kwargs) \
.replace(u'<', u'\\u003c') \
.replace(u'>', u'\\u003e') \
.replace(u'&', u'\\u0026') \
.replace(u"'", u'\\u0027')
return Markup(rv)
(You could use \x3C instead of \u003C and that would work in a script element because it's valid JavaScript. But might as well stick to valid JSON.)
First of all, your paranoia is well founded.
an HTML-parser could be tricked by a closing script tag (better assume by any closing tag)
a JS-parser could be tricked by backslashes and quotes (with a really bad encoder)
Yes, it would be much "safer" to encode all characters that could confuse the different parsers involved. Keeping it human-readable might be contradicting your security paradigm.
Note: The result of JSON String encoding should be canoncical and OFC, not broken, as in parsable. JSON is a subset of JS and thus be JS parsable without any risk. So all you have to do is make sure the HTML-Parser instance that extracts the JS-code is not tricked by your user data.
So the real pitfall is the nesting of both parsers. Actually, I would urge you to put something like that into a separate request. That way you would avoid that scenario completely.
Assuming all possible styles and error-corrections that could happen in such a parser it might be that other tags (open or close) might achieve a similar feat.
As in: suggesting to the parser that the script tag has ended implicitly.
So it is advisable to encode slash and all tag braces (/,<,>), not just the closing of a script-tag, in whatever reversible method you choose, as long as long as it would not confuse the HTML-Parser:
Best choice would be base64 (but you want more readable)
HTMLentities will do, although confusing humans :)
Doing your own escaping will work as well, just escape the individual characters rather than the </script fragment
In conclusion, yes, it's probably best with a few changes, but please note that you will be one step away from "safe" already, by trying something like this in the first place, instead of loading the JSON via XHR or at least using a rigorous string encoding like base64.
P.S.: If you can learn from other people's code encoding the strings that's nice, but you should not resort to "libraries" or other people's functions if they don't do exactly what you need.
So rather write and thoroughly test your own (de/en)coder and know that this pitfall has been sealed.
I am using rhino javascript engine to evaluate the json. The Json structure is as following :
{"DataName":"111","Id":"222","Date":"2015-12-31T00:00:00","TextValue":"{\"Id\":\"1\",\"Name\":\"Daugherty\",\"ContactName\":\"May C\",\"ContactEmail\":\"may.c#gamil.com\",\"Total\":25,\"Phone\":\"111-111-1111\",\"Type\":\"Daily\",\"Notes\":[{\"Comments\":\"One\",\"Date\":\"2014-11-27T00:00:00.000\"},{\"Comments\":\"Two\",\"Date\":\"2014-11-28T00:00:00.000\"}],\"ImportComplete\":true,\"RunComplete\":true,\"CompleteDate\":\"2014-07-31T00:00:00.000\",\"Amount\":2400.00,\"ProcessingComplete\":true}","NumberValue":4444.5555,"DateValue":"2014-12-01T00:00:00"}
Since I am using Rhino js engine I can't use JSON.parse and JSON.stringify.
As you can see the json has embedded json, this json I am getting from a .net web api which is putting the escape character '\'. I am trying to replace that escape character in javascript but no help.
Is there any way in javascript where we can replace that escape character and use 'eval()' to evaluate the json.
Here's the code that I am trying
var json = '{"DataName":"111","Id":"222","Date":"2015-12-31T00:00:00","TextValue":"{\"Id\":\"1\",\"Name\":\"Daugherty\",\"ContactName\":\"May C\",\"ContactEmail\":\"may.c#gamil.com\",\"Total\":25,\"Phone\":\"111-111-1111\",\"Type\":\"Daily\",\"Notes\":[{\"Comments\":\"One\",\"Date\":\"2014-11-27T00:00:00.000\"},{\"Comments\":\"Two\",\"Date\":\"2014-11-28T00:00:00.000\"}],\"ImportComplete\":true,\"RunComplete\":true,\"CompleteDate\":\"2014-07-31T00:00:00.000\",\"Amount\":2400.00,\"ProcessingComplete\":true}","NumberValue":4444.5555,"DateValue":"2014-12-01T00:00:00"}';
var find = '\"';
var regex = new RegExp(find,'g');
var inj = json.replace(regex,'"');
var pl = eval('(' + inj +')');
confusing backslashes
The problem you are getting is due to the fact of not fully understanding escape characters, when you are more than one level of "string" deep. Whilst a single slash is fine for one level i.e:
"It is no coincidence that in no known language does the " +
"phrase \"As pretty as an Airport\" appear.";
If you take that and then wrap it in outer quotes:
'"It is no coincidence that in no known language does the "' +
'"phrase \"As pretty as an Airport\" appear."';
The backslashes (if supported as escape characters by the system parsing the string) work for the outer-most wrapping quote, not any of the inner quotes/strings as they were before. This means once the js engine has parsed the string, internally the string will be.
'"It is no coincidence that in no known language does the phrase "As pretty as an Airport" appear."';
Which makes it impossible to tell the difference between the " and the \" from the original string. In order to get around this, you need to escape the backslashes in the original string, before you wrap it. This has the result of one level of escaping being used by the JavaScript engine, but still leaving another level remaining within the string. e.g.
'"It is no coincidence that in no known language does the "' +
'"phrase \\"As pretty as an Airport\\" appear."';
Now when the string is parsed, internally it will be:
'"It is no coincidence that in no known language does the phrase \"As pretty as an Airport\" appear."';
ignore the my random Douglas Adams quotes being separated onto more than one line (using +), I've only done that for ease of reading within a fix width area. I've kept it parsable by JavaScript, just in case people copy and paste and expect things to work.
So in order to fix your issue, your JSON source (before placing in the JavaScript code) will have to look like this:
var json = '{"DataName":"111","Id":"222","Date":"2015-12-31T00:00:00","TextValue":"{\\"Id\\":\\"1\\",\\"Name\\":\\"Daugherty\\",\\"ContactName\\":\\"May C\\",\\"ContactEmail\\":\\"may.c#gamil.com\\",\\"Total\\":25,\\"Phone\\":\\"111-111-1111\\",\\"Type\\":\\"Daily\\",\\"Notes\\":[{\\"Comments\\":\\"One\\",\\"Date\\":\\"2014-11-27T00:00:00.000\\"},{\\"Comments\\":\\"Two\\",\\"Date\\":\\"2014-11-28T00:00:00.000\\"}],\\"ImportComplete\\":true,\\"RunComplete\\":true,\\"CompleteDate\\":\\"2014-07-31T00:00:00.000\\",\\"Amount\\":2400.00,\\"ProcessingComplete\\":true}","NumberValue":4444.5555,"DateValue":"2014-12-01T00:00:00"}';
You should find the above will eval directly, without any replacements.
In order to achieve the above programatically, you will have to see what the .NET system you are using offers in the way of escaping backslashes. I mainly work with PHP or Python on the server side. Using those languages you could use:
the $s and s strings below have been cropped for brevity.
<?php
$s = '{"DataName":"111","Id":"222"...';
$s = str_replace("\\", "\\\\", $s);
echo "var json = '$s';";
or ...
#!/usr/bin/env python
s = r'{"DataName":"111","Id":"222"...'
s = s.replace("\\", "\\\\")
print "var json = '" + s + "';"
another solution
It all depends on how you are requesting the content you are wrapping in the string in JavaScript. If you have the ability to write out your js from the server side (most likely with .NET). Like I have shown above with PHP or Python, you don't need to wrap the content in a string at all. You can instead just output the content without being wrapped in single quotes. JavaScript will then just parse and treat it as a literal object structure:
var jso = {"DataName":"111","Id":"222","Date":"2015-12-31T00:00:00","TextValue":"{\"Id\":\"1\",\"Name\":\"Daugherty\",\"ContactName\":\"May C\",\"ContactEmail\":\"may.c#gamil.com\",\"Total\":25,\"Phone\":\"111-111-1111\",\"Type\":\"Daily\",\"Notes\":[{\"Comments\":\"One\",\"Date\":\"2014-11-27T00:00:00.000\"},{\"Comments\":\"Two\",\"Date\":\"2014-11-28T00:00:00.000\"}],\"ImportComplete\":true,\"RunComplete\":true,\"CompleteDate\":\"2014-07-31T00:00:00.000\",\"Amount\":2400.00,\"ProcessingComplete\":true}","NumberValue":4444.5555,"DateValue":"2014-12-01T00:00:00"};
This works because JSON is just a more strict version of a JavaScript Object, and the quote/escape level you already have will work fine.
The only downside to the above solution is that you have to implicitly trust the source of where you are getting this data from, and it will always have to be well formed. If not, you could introduce parse errors or unwanted js into your code; which could be avoided with an eval/JSON.parse system.
Is there any method to find out if the given string is HTML Escaped or not?
Consider the following javascript code:
<script>
var str="hello";
var str_esc=escape(str);
document.write(isHTMLEscaped(str)) // *Should print False*
document.write(isHTMLEscaped(str_esc)); // *Should print True*
</script>
Is there any method equivalent to isHTMLEscaped in the above case?
I found that using
escape(unescape(str))
will always provide an escaped string. And the unescape string will do nothing unless the string itself contains escaped expressions.
Note: should have used encodeURI(decodeURI(str)) instead as escape is now depreciated.
As "hello"==escape("hello"), no, you can't at all guess if escaping was applied.
If you want to know if it's probable that the string has been escaped, then you might test
var wasProbablyEscaped = /%\d\d/.test(str);
var wasProbablyNotEscaped = !wasProbablyEscaped && /%\d\d/.test(escape(str));
as escaping adds % followed by two digits when something has to be escaped. But you can't be totally sure as some strings don't change when you escape them.
In your case, I'd probably advise you not to escape if wasProbablyEscaped is true.
I have a JS file with some XML in it, where the XML is supposed to get converted to a word by the server.
E.g.
var ip = "<lang:cond><lang:when test="$(VAR{'ip_addr'})">$(VAR{'ip_addr'})</lang:when></lang:cond>";
This gets converted to:
var ip = "192.168.0.0";
However, in case the server doesn't work as intended, I don't want there to be a syntax error, and this is VERY important. Currently there would be a syntax error because the language uses both types of quotes. I can't think of a way to get around this, but perhaps there's another way to do quotes in JavaScript? Or to create a string?
For example, in Python I'd use triple quotes:
ip = """<lang:cond><lang:when test="$(VAR{'ip_addr'})">$(VAR{'ip_addr'})</lang:when></lang:cond>"""
Anyone have a bright idea?
I have had to create strings without quotes for a project as well. We were delivering executable client javascript to the browser for an internal website. The receiving end strips double and single quotes when displayed. One way I have found to get around quotes is by declaring my string as a regular expression.
var x = String(/This contains no quotes/);
x = x.substring(1, x.length-1);
x;
Using String prototype:
String(/This contains no quotes/).substring(1).slice(0,-1)
Using String.fromCharCode
String.fromCharCode(72,69,76,76,79)
Generate Char Codes for this:
var s = "This contains no quotes";
var result = [];
for (i=0; i<s.length; i++)
{
result.push(s.charCodeAt(i));
}
result
In JavaScript, you can escape either type of quote with a \.
For example:
var str = "This is a string with \"embedded\" quotes.";
var str2 = 'This is a string with \'embedded\' quotes.';
In particular, your block of JavaScript code should be converted to:
var ip = "<lang:cond><lang:when test=\"$(VAR{'ip_addr'})\">$(VAR{'ip_addr'})</lang:when></lang:cond>";
In general, I always prefer to escape the quotes instead of having to constantly switch quote types, depending upon what type of quotes may be used within.
I was looking for a solution to the same problem. Someone suggested looking at https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/template_strings which proved helpful. After reading about half the article, it stated that you can create strings with the backward tick character. (`)
Try this :)
document.getElementById('test').innerHTML = `'|'|'|"|"`
<div id="test" style="font-size:3em;"></div>
You can't create a string without using a single or double quote, as even calling the String() prototype object directly still requires you to pass it the string.
Inside XML you would use CDATA, but inside JS you'll have to just escape the '\"strings\"' "\'appropriately\'"