ES2015 template strings security issue - javascript

Here's a quote from MDN:
Template strings MUST NOT be constructed by untrusted users, because they have access to variables and functions.
And an example:
`${console.warn("this is",this)}`; // "this is" Window
let a = 10;
console.warn(`${a+=20}`); // "30"
console.warn(a); // 30
The example here doesn't show any vulnerabilities I can see.
Can anyone give an example of an exploit that takes advantage of this?

This makes no sense. A template string doesn't have access to anything, it is not executed either. A template string is a syntactical element of the language.
Dynamically constructing a template string is no problem therefore - it's like building an expression (in whatever format, be it a code string or an AST). The problem MDN hints at is with evaluating such an expression (e.g. using eval, serialising it into a script that is served to the user, etc.) - it may contain arbitrary code, in contrast to a string literal! But of course you wouldn't do that anyway, would you?
This warning is like saying "Concatenations using the + operator must not be constructed by untrusted users, because they have access to variables and functions." and giving the example "" + console.warn("this is",this) + "" for it. Well, this is true for any expression of the language, so it's not particularly interesting.
While we are talking about crappy coding, there is of course a scenario where using template strings (hey, they're multiline and whatnot) instead of string literals can lead to problems:
function escapeString(str) {
return JSON.stringify(str).slice(1, -1)
.replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
}
// This is (kinda) fine!
var statement = 'var x = "Hello,\\n'+escapeString(userInput)+'";';
eval(statement); // some kind of evaluation
// But this is not:
var statement = 'var x = `Hello,\n'+escapeString(userInput)+'`;';
// ^ ^
Now imagine userInput contains a ${…} - which we did not escape…

I think #Bergi is correct - the danger here involves using eval or similar methods to allow a user to construct the actual template string, not the substitutions.
Example exploit: A lazy developer wants to allow users to perform some string substitutions in their comments, e.g. to reference other users or questions, on a site like SO. Instead of developing tokens for this and then doing appropriate parsing and substitution, he decides he'll accept syntax like this:
"I think ${firstPoster} is an idiot! See ${question(1234)} for details!"
and run it through a function like this:
var firstPoster = {...};
function question() {...}
processInput(input) {
return eval('`' + input + '`');
}
If this code is eval'd on the client and shown to other users, a malicious user could inject an XSS attack. If it's eval'd on the server, the attacker could take control of the machine.

The example no longer seems to be in the MDN docs. As Bergi's answer points out, the given example doesn't seem to highlight anything special about template strings.
However, when it comes to building strings from objects, there is a particular security concern you should definitely be aware of:
The toString() method will be called implicitly on a non-string object if it is passed to a string interpolation / concatenation expression.
There are probably also other cases where toString() is called implicitly. But string interpolation seems to me to be one of the most common ones; indeed, it's one I experience regularly. For example, suppose you somehow receive an object from somewhere external e.g. via an iframe through postMessage. In that case, you might want to do something like log the message received to the console - and you might be tempted to just pass the object right into an interpolated string.
But the sender (possibly an attacker) has full control over the definition of toString() and can insert whatever code they like in there. So as soon as you pass that object to the interpolated or concatenated string, you are vulnerable as long as someone else controls the definition of said object.
Here is a simple example (added to codesandbox), showing that even if objects return seemingly harmless strings in toString(), they can indeed do dangerous stuff like read you local storage:
import "./styles.css";
localStorage.setItem("secret1", "sssh! One");
localStorage.setItem("secret2", "sssh! Two");
const evilObject1 = {
toString() {
alert("I stole a secret: " + localStorage.getItem("secret1"))
return "I'm innocent";
}
};
const evilObject2 = {
toString() {
alert("I stole a secret: " + localStorage.getItem("secret2"))
return "I'm innocent";
}
};
const strInter = `Seemingly innocent object, interpolated: ${evilObject1}`;
const strConcat = "Seemingly innocent object, concatenated: " + evilObject2;
let p = document.createElement("p");
p.innerHTML = strInter
let p2 = document.createElement("p");
p2.innerHTML = strConcat
document.body.appendChild(p);
document.body.appendChild(p2);
With Javascript, being duck-typed, this is quite a real vulnerability, because you might think that the object you receive (e.g. via postMessage) is a string, and indeed, it may behave like a string (because it has a cleverly designed toString() method), but unless you dynamically check the types you don't know if you actually got a string.
If you're expecting a string, you can fix the above vulnerability as follows:
const sanitized1 = typeof evilObject1 === 'string' ? evilObject1 : "BAD OBJECT1"
const sanitized2 = typeof evilObject2 === 'string' ? evilObject2 : "BAD OBJECT2"
const strInter = `Seemingly innocent object, interpolated: ${sanitized1}`;
const strConcat = "Seemingly innocent object, concatenated: " + sanitized2;
With this fix, you avoid implicitly calling toString() on an unsafe object. Either the objects you got were strings, and those will be used, or else they weren't, and you'll get the "BAD OBJECT" text instead.

Related

What is the default “tag” function for template literals?

What is the name of the native function that handles template literals?
That is, I know that when you write tag`Foo ${'bar'}.`;, that’s just syntactic sugar for tag(['Foo ', '.'], 'bar');.¹
But what about just ​`Foo ${'bar'}.`;? I can’t just “call” (['Foo ', '.'], 'bar');. If I already have arguments in that form, what function should I pass them to?
I am only interested in the native function that implements the template literal functionality. I am quite capable of rolling my own, but the purpose of this question is to avoid that and do it “properly”—even if my implementation is a perfect match of current native functionality, the native functionality can change and I want my usage to still match. So answers to this question should take on one of the following forms:
The name of the native function to use, ideally with links to and/or quotes from documentation of it.
Links to and/or quotes from the spec that defines precisely what the implementation of this function is, so that if I roll my own at least I can be sure it’s up to the (current) specifications.
A backed-up statement that the native implementation is unavailable and unspecified. Ideally this is backed up by, again, links to and/or quotes from documentation, but if that’s unavailable, I’ll accept other sources or argumentation that backs this claim up.
Actually, the first argument needs a raw property, since it’s a TemplateStringsArray rather than a regular array, but I’m skipping that here for the sake of making the example more readable.
Motivation
I am trying to create a tag function (tag, say) that, internally, performs the default template literal concatenation on the input. That is, I am taking the TemplateStringsArray and the remaining arguments, and turning them into a single string that has already had its templating sorted out. (This is for passing the result into another tag function, otherTag perhaps, where I want the second function to treat everything as a single string literal rather than a broken up template.)
For example, tag`Something ${'cooked'}.`; would be equivalent to otherTag`Something cooked.`;.
My current approach
The definition of tag would look something like this:
function tag(textParts, ...expressions) {
const cooked = // an array with a single string value
const raw = // an array with a single string value
return otherTag({ ...cooked, raw });
}
Defining the value of raw is fairly straightforward: I know that String.raw is the tag function I need to call here, so const raw = [String.raw(textParts.raw, ...expressions)];.
But I cannot find anywhere on the internet what function I would call for the cooked part of it. What I want is, if I have tag`Something ${'cooked'}.`;, I want const cooked = `Something ${cooked}.`; in my function. But I can’t find the name of whatever function accomplishes that.
The closest I’ve found was a claim that it could be implemented as
const cooked = [expressions.map((exp, i) => textParts[i] + exp).join('')];
This is wrong—textParts may be longer than expressions, since tag`Something ${'cooked'}.`; gets ['Something ', '.'] and ['cooked'] as its arguments.
Improving this expression to handle that isn’t a problem:
const cooked = [
textParts
.map((text, i) => (i > 0 ? expressions[i-1] : '') + text)
.join(''),
];
But that’s not the point—I don’t want to roll my own here and risk it being inconsistent with the native implementation, particularly if that changes.
The name of the native function to use, ideally with links to and/or quotes from documentation of it.
There isn't one. It is syntax, not a function.
Links to and/or quotes from the spec that defines precisely what the implementation of this function is, so that if I roll my own at least I can be sure it’s up to the (current) specifications.
Section 13.2.8 Template Literals of the specification explains how to process the syntax.

Am i using eval() safely in server?

To put it shortly, i am using the eval to dynamically call functions (that all have same name in front and the last bit differs) that i use for validating a client's cookies.
const cookie_names = ['cookiename_1', 'cookiename_2'];
exports.validateCookies = (req, res, next) => {
const cookie_types = filterUnknownCookies(Object.keys(req.cookies));
for(let cookie of cookie_types){
res.locals[cookie] = eval(`validateCookie${cookie}('${req.cookies[cookie]}')`);
}
next();
}
const filterUnknownCookies = (cookie_arr) => {
cookie_arr = cookie_arr.filter(name => cookie_names.findIndex( validnames => validnames === name) + 1);
return cookie_arr;
}
Since i knew that using the eval function might be dangerous, i hardcoded the valid cookie names and filtered anything that didn't match them in the array.
So the question: is filtering the array from any unwanted strings (names) safe enough to counter the eval's exploitability?
Thanks in advance 🧡🧡
So the question: is filtering the array from any unwanted strings (names) safe enough to counter the eval's exploitability?
No. This is not safe. In fact, it does basically nothing to safeguard you because the cookie names you allow are still completely unguarded and unsanitized. What you have is potentially unsafe because a malicious client can put anything they want in that cookie and you're "hoping" that they can't find something that will break out of the string delimiter you have. But, it is possible to break out of that string delimiter by just terminating the string and then adding a function call. This would potentially allow an attacker to execute arbitrary code on your server.
The ONLY thing you should ever use eval() with is a trusted string from your own server-side code or a completely sanitized string form the outside. But, nearly always, you don't need eval() as there is another and safer way to code it.
Here, you don't need to use eval() at all. You can just create a lookup table for the legal functions to call and then pass the function directly to it:
try {
res.locals[cookie] = validateCookie[cookie](req.cookies[cookie]);
} catch(e) {
// either invalid cookie or exception in the function
// handle that here
}
And, of course, your validateCookie[cookie]() function also has to be coded defensively to know that it may be passed anything. You don't show us the code for that function to be able to comment on it further.
In this case, validateCookie is a lookup table that contains the valid cookie names and their corresponding functions:
// cookie processing lookup table
const validateCookie = {
cookieName1: validateCookieName1,
cookieName2: validateCookieName2
};
Lookup tables like this are often how you avoid trying to manufacture a function name and a string and use eval() to call it. This also adds the safety feature that this code can't call any function that is not in your lookup table.
No the code is not safe, not because it doesn't sanitize the name of the validation method, but because it evaluates uploaded text as JavaScript when expanding the string template literal:
`... ${req.cookies[cookie]} ...`
I just tested and injected code using a carefully crafted string value for req.cookies[cookie], which I will refrain from publishing here.
It may be slightly safer to evaluate the validation call without expanding the data string, as in
`validateCookie${cookie}` + "(req.cookies[cookie])"
which would pass uploaded text to the validation routine without evaluation as code, but the safety of avoiding eval altogether remains the same. Avoiding eval can easily be achieved by using a lookup table of validation function object values keyed by function name.

Create object from text

I have javascript text:
var textObject = '
{
news: [
{
"title":"aaa",
"desc":"bbb"
}, {
"title":"ccc",
"desc":"ddd"
} ]
};
'
but this is in text in my variable. If i have this in code html this working ok, but i get this data with ajax from PHP script.
So how can i convert/parse this text to object? If i have JSON then i can use JSON.parse(textObject); but this isn't json.
Eval is frowned upon for a lot of reasons, however it also has its benefits if used properly, it is used for a lot of template engines and a few other things but it will convert a string to an object.
var someString = '{obj: "with content"}';
eval( someString );
Here is a working example with your string: http://jsfiddle.net/kkemple/CwzRh/
Using eval can result in serious performance degradation.
Since you can't do JSON, then use the Function constructor instead so that the evaling takes place in the global scope, and the browsers can still optimize the local code.
var result = new Function("return " + textObject.trim())();
You'll need to shim .trim() to support IE8. If the string is as you show with line breaks at the beginning, then the .trim() will be necessary.

How to convert a string equation to a numeric value with Javascript

Basically, I have a user input field where a user can enter a number. They would like to also be able to enter equations in the input field as well.
Something like "874.45 * 0.825 + 4000" and have that converted to its real numeric value.
All the solutions I found point to the dreaded eval() method. Especially with this being a user entered field, I'm concerned about just running eval("874.45 * 0.825 + 4000") and hoping to get a number out the back end.
I suppose I could do a web service call back to the server (ASP.NET), but I'm afraid a slight delay will create some frustration from the user.
Does anyone know of either a good technique or existing libraries?
What you really need here is an "expression parser", because you're trying to allow users to express their values using a small domain-specific language.
The basic mechanics work like this:
Tokenize their expression into operators and operands.
Based on the order of operations (e.g, where multiplication is evaluated with higher priority than addition), push the operators and operands onto a stack.
Pop the operands from the stack and push intermediate results back onto the stack. Repeat until the stack is empty.
I've done this a gazillion times for different "little languages" throughout my projects. But never in javascript. So I can't directly recommend a suitable parsing library.
But a quick googling reveals "PEG.js". Check it out here:
http://pegjs.majda.cz/
All of the examples in their documentation are for exactly the kind of "expression parser" you're trying to build.
Simply multiply it by 1 and it will force javascript to treat it as an integer from then on.
Eg
int = '2343.34' * 1;
int = input * 1;
And what is so wrong about the eval in this case?
As for me it perfectly fits in your task. If you want to shield its execution context then you can define function like:
function calc(str) {
var window = null, self = null, document = null;
// other globals like: $ = null, jQuery = null, etc.
try { return eval(str); } catch(e) {...}
}
and use it where you need to interpret the string. Simple and effective.
I think eval can pose a lesser security risk if you parse the resulting string and validate its content to be only digits and operators and execute the evaluation by faking the outer scope variables like document etc as 'var document = null'.

Calling toString on a javascript function returns source code

I just found out that when you call toString() on a javascript function, as in myFunction.toString(), the source code of that function is returned.
If you try it in the Firebug or Chrome console it will even go as far as formatting it nicely for you, even for minimized javascript files.
I don't know what is does for obfuscated files.
What's the use of such a toString implementation?
It has some use for debugging, since it lets you see the code of the function. You can check if a function has been overwritten, and if a variable points to the right function.
It has some uses for obfuscated javascript code. If you want to do hardcore obfuscation in javascript, you can transform your whole code into a bunch of special characters, and leave no numbers or letters. This technique relies heavily on being able to access most letters of the alphabet by forcing the toString call on everything with +""
example: (![]+"")[+[]] is f since (![]+"") evaluates to the string "false" and [+[]] evaluates to [0], thus you get "false"[0] which extracts the first letter f.
Some letters like v can only be accessed by calling toString on a native function like [].sort. The letter v is important for obfuscated code, since it lets you call eval, which lets you execute anything, even loops, without using any letters. Here is an example of this.
function.ToString - Returns a string representing the source code of the function. For Function objects, the built-in toString method decompiles the function back into the JavaScript source that defines the function.
Read this on mozilla.
You can use it as an implementation for multi-line strings in Javascript source.
As described in this blog post by #tjanczuk, one of the massive inconveniences in Javascript is multi-line strings. But you can leverage .toString() and the syntax for multi-line comments (/* ... */) to produce the same results.
By using the following function:
function uncomment(fn){
return fn.toString().split(/\/\*\n|\n\*\//g).slice(1,-1).join();
};
…you can then pass in multi-line comments in the following format:
var superString = uncomment(function(){/*
String line 1
String line 2
String line 3
*/});
In the original article, it was noted that Function.toString()'s behaviour is not standardised and therefore implementation-discrete — and the recommended usage was for Node.js (where the V8 interpreter can be relied on); however, a Fiddle I wrote seems to work on every browser I have available to me (Chrome 27, Firefox 21, Opera 12, Internet Explorer 8).
A nice use case is remoting. Just toString the function in the client, send it over the wire and execute it on the server.
My use case - I have a node program that processes data and produces interactive reports as html/js/css files. To generate a js function, my node code calls myfunc.toString() and writes it to a file.
You can use it to create a Web Worker from function defined in the main script:
onmessage = function(e) {
console.log('[Worker] Message received from main script:',e.data);
postMessage('Worker speaking.');
}
b = new Blob(["onmessage = " + onmessage.toString()], {type: 'text/javascript'})
w = new Worker(window.URL.createObjectURL(b));
w.onmessage = function(e) {
console.log('[Main] Message received from worker script:' + e.data);
};
w.postMessage('Main speaking.');

Categories

Resources