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.
Related
I've seen a lot about how the eval() function is evil; not a wise choice for HTML/JavaScript programming. I would like to use a function where I can pass in a string to have it read as a variable name, and eval() seems to do just that, but I don't want to use a destructive function.
From what I understand, the issue with eval() is that it can read third-party input as actual code, which opens a door for malicious activity. I have a map element that keeps track of location using strings for the location names. I also have large blocks of text assigned to variables so I can pull up a description of the current location easily. This seems like an acceptable time to use eval, as the strings that I would be passing in would be provided by other parts of the code. Is this a fair judgement, or is there some other function that I should be using?
(Moving my comment as an answer)
An easy way to get around that is to save whatever variable you're interested in accessing in a javascript Object (i.e. key-value pairs), and access them via indexing. This simple use case doesn't need eval.
From what I understand, the issue with eval() is that it can read third-party input as actual code, which opens a door for malicious activity.
This is not the only reason. One could argue that by today's standards the performance of JavaScript code is negligible.
However, one has to take into account that eval() actually invokes the JavaScript interpreter which is significantly slower than writing the code upfront. ¹
I would like to use a function where I can pass in a string to have it read as a variable name, and eval() seems to do just that, but I don't want to use a destructive function.
This does not warrant the use of eval(). As mentioned in the comments, you can achieve this with keeping track of variables in an object:
let vars = {}
vars["some_variable_name"] = "test"
const var_name = "some_variable_name"
console.log(vars[var_name]) // "test"
as the strings that I would be passing in would be provided by other parts of the code
Might be, but what if in the future some piece of that code actually does process some user input?
Not worth the performance penality and obvious security risk in my opinion.
For a simple way to use a variable name as a string is to use an Object (called a dictionary or map in some languages)
const stringToGrade = {
"freshman": 9,
"sophomore": 10,
"junior": 11,
"senior": 12,
};
document.querySelector("#btn").addEventListener("click", () => {
const asString = document.querySelector("#inp").value.toLowerCase();
const grade = stringToGrade[asString];
console.log(`Your grade number is ${grade}`);
});
<input id="inp" placeholder="Enter your grade level (freshman, sophomore, etc.)" />
<button id="btn">Submit</button>
Here's a SOAP response that I want to use javascript to extract a list of key value pairs where the key is the local namespace element prefix, such as:
SOAP-ENVns98ns70
and the value is the namespace definition, such as:
http://schemas.xmlsoap.org/soap/envelope/urn:vertexinc:enterprise:platform:security:messages:1:0urn:vertexinc:enterprise:platform:security:1:0
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<ns98:ExecuteLoginResponse
xmlns:ns70="urn:vertexinc:enterprise:platform:security:1:0"
xmlns:ns98="urn:vertexinc:enterprise:platform:security:messages:1:0">
<ns70:UserLoginConfirmation>
<ns70:UserName>platformadmin</ns70:UserName>
<ns70:LoginResult>SUCCESS</ns70:LoginResult>
<ns70:LastLoginDate>2016-01-26T17:28:02.109</ns70:LastLoginDate>
<ns70:DefaultAsOfDate>2016-01-26</ns70:DefaultAsOfDate>
<ns70:ForcePasswordChange>false</ns70:ForcePasswordChange>
</ns70:UserLoginConfirmation>
</ns98:ExecuteLoginResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
My research thus far indicates a general lack of need to do something like this, most people either strip the name space from the elements of the part of the document that they care about, or they simply ignore the namespace. At the moment I am stripping the namespace values, but for debugging purposes would like to inspect the namespaces that were used in the response.
An interesting aspect of the service being used is that the nsXX values can vary for each invocation (e.g. ns70 could be ns78 next time the method is invoked). This means that I cannot key on a fixed namespace value. Additionally, the namespace values for these messages in the WSDL don't seem to have any correspondence to the namespace values in the response.
XPath seems like it might be able to help here, or I could just write my own, but I'd prefer to leverage an existing approach. At this point I'm just trying to understand the problem space and would appreciate some guidance with regard to where to start my education process. (please point me in the right direction)
The approach I took was to fork angular-soap and add the ability to build a list of response namespaces as the XML response is converted into an object tree:
SOAPClient._node2object = function (node, wsdlTypes, namespaces) {
var namespaceURI = node.namespaceURI;
var prefix = node.prefix;
if ('undefined' != typeof namespaceURI) {
namespaces[prefix] = namespaceURI;
}
...
}
To get the list of namespaces a namespaces object must be passed to the $soap.post() method, as follows.
var namespaces = new Object();
...
$soap.post(webserviceurl, "SomeWebservice", parameters, namespaces).then(function (response) {
...
}
The alteration to the angular-soap code required modification of all functions between the $soap.post(url, action, parameters, namespaces) method and SOAPClient._node2object(node, wsdlTypes, namespaces) function to propagate the namespaces parameter.
http://www.w3schools.com/xml/dom_element.asp
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.
I've been searching around for a simple-lightweight hashing algorithm for JavaScript. I did find this numerically-based answer on Stack Overflow here.
Unfortunately, I am unable to use this since it's numerically based and I'll need to use this hash as a unique index elsewhere in my code. Often this function returns negative numbers and that would be a big no-no (try 'hello world!'.hashCode() from the snippet linked above to see what I mean).
I've been tempted to use the md5 hashing libraries out there for JS but they're simply to bulky for my purpose and encryption libraries (such as this) are overkill.
It's worth noting that the information within this hash isn't sensitive in anyway and it wouldn't necessarily matter if it was decrypted. The purpose of this function would be to simply generate fixed-length output data that acts as a shortened reference to the original data that I would pass in.
Any help, tips and comments are much appreciated :)
The solution proposed by Kooilnc, to use the absolute value, should do the tric for you. However, if you want to use a hashing function to generate a reference, i assume that the reference you get should be unique as to match the exact element it was generated from. If this is the case, be aware of collisions. Hashing function can create hashes that are similar even though the original messages are different and we call this a collision. If i remember correctly, SHA-1 is also available for java script and is not all that bulk. Good luck
I am unable to use this since it's numerically based and I'll need to use this hash as a unique index elsewhere in my code.
Hash functions are normally numerically based and are rarely perfect (produce unique keys). I think you need something different:
function GuidGen()
{
this.items = {};
this.size = 0;
}
GuidGen.prototype.get = function(str)
{
if (!(str in this.items))
{
this.items[str] = this.size++;
}
return this.items[str];
}
// usage:
id = new GuidGen();
id.get("hello world"); // 0
id.get("spam"); // 1
id.get("eggs"); // 2
id.get("hello world"); // 0
I am have some JavaScript functions that run on both the client (browser) and the server (within a Java Rhino context). These are small functions - basically little validators that are well defined and don't rely upon globals or closures - self-contained and portable.
Here's an example:
function validPhoneFormat(fullObject, value, params, property) {
var phonePattern = /^\+?([0-9\- \(\)])*$/;
if (value && value.length && !phonePattern.test(value))
return [ {"policyRequirement": "VALID_PHONE_FORMAT"}];
else
return [];
}
To keep things DRY, my server code gets a handle on each of these functions and calls toString() on them, returning them to the browser as part of a JSON object. Something like this:
{ "name" : "phoneNumber",
"policies" : [
{ "policyFunction" : "\nfunction validPhoneFormat(fullObject, value, params, property) {\n var phonePattern = /^\\+?([0-9\\- \\(\\)])*$/;\n if (value && value.length && !phonePattern.test(value)) {\n return [{\"policyRequirement\":\"VALID_PHONE_FORMAT\"}];\n } else {\n return [];\n }\n}\n"
}
]
}
My browser JS code then takes this response and creates an instance of this function in that context, like so:
eval("var policyFunction = " + this.policies[j].policyFunction);
policyFailures = policyFunction.call(this, form2js(this.input.closest("form")[0]), this.input.val(), params, this.property.name));
This all works very well. However, I then run this code through JSLint, and I get back this message:
[ERROR] ValidatorsManager.js:142:37:eval is evil.
I appreciate that often, eval can be dangerous. However, I have no idea how else I could implement such a mechanism without using it. Is there any way I can do this and also pass through the JSLint validator?
I wouldn't worry about it since you are only passing these function strings from the server to the client, and are thus in control of what will be evaluated.
On the other hand, if you were going the other direction and doing the evals of client-passed code on the server, that would be an entirely different story...
Update:
As disabling the validation option in your comment may cause you to miss future errors, I would instead suggest passing the function name rather than the entire function and have the function library mirrored on the server and client. Thus, to call the function, you'd use the following code:
var policyFunction = YourLibraryName[this.policies[j].policyFunctionName];
var policyArguments = this.policies[j].policyArguments;
policyFunction.apply(this, policyArguments);
Update 2:
I was able to validate the following code with JSLint successfully, which essentially allows you to "turn off" validation for the vast minority of cases where eval is appropriate. At the same time, JSLint still validates normal eval calls, and all uses of this method should throw up flags for future developers to avoid using it/refactor it out where possible/as time allows.
var EVAL_IS_BAD__AVOID_THIS = eval;
EVAL_IS_BAD__AVOID_THIS(<yourString>);
Dont encode a function as a string in JSON. JSON is for content, which you are confounding with behavior.
Instead, I suppose you could return JS files instead, which allow real functions:
{ name : "phoneNumber",
policies : [
{ policyFunction : function() {
whateverYouNeed('here');
}
}
]
}
But while that solves the technical issue, it's still not a great idea.
The real solution here is to move your logic out of your content entirely. Import a JS file full of little validation functions and call them as needed based on a dataType property in your JSON or something. If this functions are as small and portable as you say, this should be trivial to accomplish.
Getting your data all tangled up with your code usually leads to pain. You should statically include your JS, then dynamically request/import/query for your JSON data to run through your statically included code.
I would avoid using eval in all situations. There's no reason you can't code around it. Instead of sending code to the client, just keep it hosted on the server in one contained script file.
If that's not doable, you can also have a dynamically generated javascript file then pass in the necessary parameters via the response, and then dynamically load the script on the client side. There's really no reason to use eval.
Hope that helps.
You can use
setInterval("code to be evaluated", 0);
Internally, if you pass setInterval a string it performs a function similar to eval().
However, I wouldn't worry about it. If you KNOW eval() is evil, and take appropriate precautions, it's not really a problem. Eval is similar to GoTo; you just have to be careful and aware of what you're doing to use them properly.
With very little parsing you could have had it like so:
var body = this.policies[j].policyFunction.substr;
body = body.substr(body.indexOf("(") + 1);
var arglist = body.substr(1, body.indexOf(")"));
body = body.substr(arglist.length + 1);
var policyFunction = new Function(arglist, body);
Which would provide a bit of validation, avoid the literal use of eval and work synchronously with the code. But it is surely eval in disguise, and it is prone to XSS attack. If the malevolent person can get their code loaded and evaluated this way - it will not save you. So, really, just don't do it. Add a <script> tag with the proper URL and that would be certainly safer. Well, you know, better safe then sorry.
PS. My apologises if the code above doesn't work, it only shows the intent, I've not tested it, and if I made a mistake at counting parenthesis or some such - well, you should get the idea, I'm not advertising it by any means.
DRY is definitely something I agree with, however there is a point where copy+pasting is more efficient and easy to maintain than referencing the same piece of code.
The code you're saving yourself from writing seems to be equivalent to a clean interface, and simple boiler plate. If the same code is being used on both the server and the client, you could simply pass around the common pieces of the function, rather than the whole function.
Payload:
{
"name": "phoneNumber",
"type": "regexCheck",
"checkData": "/^\\+?([0-9\\- \\(\\)])*$/"
}
if(payload.type === "regexCheck"){
const result = validPhoneFormat(fullObject, value, payload.checkData)
}
function validPhoneFormat(fullObject, value, regexPattern) {
if (value && value.length && !regexPattern.test(value))
return [ {"policyRequirement": "VALID_PHONE_FORMAT"}];
else
return [];
}
This would give you the ability to update the regex from a single location. If the interface changes it does need to be updated in 2 places, but I wouldn't consider that a bad thing. If the client is running code, why hide the structure?
If you really, really want to keep both the object structure and the patterns in one place - extract it to a single API. Have a "ValidatePhoneViaRegex" api endpoint which is called by all places you'd be passing this serialized function to.
If all of this seems like too much effort, set jslint to ignore your piece of code:
"In JSHint 1.0.0 and above you have the ability to ignore any warning with a special option syntax. The identifier of this warning is W061. This means you can tell JSHint to not issue this warning with the /*jshint -W061 */ directive.
In ESLint the rule that generates this warning is named no-eval. You can disable it by setting it to 0, or enable it by setting it to 1."
https://github.com/jamesallardice/jslint-error-explanations/blob/master/message-articles/eval.md
I would prefer to see copy+pasted code, a common api, or receiving parameters and copy+pasted boiler plate than magical functions passed in from the server to be executed.
What happens if you get a cross-browser compatibility error with one of these shared functions?
Well, the first thing to bear in mind is that jsLint does make the point that "it will hurt your feelings". It's designed to point out where you're not following best practices -- but code that isn't perfect can still work just fine; there's no compulsion upon you to follow jsLint's advice.
Having said that, eval is evil, and in virtually all cases there is always a way around using it.
In this case, you could use a library such as require.js, yepnope.js or some other library that is designed to load a script separately. This would allow you to include the javascript functions you need dynamically but without having to eval() them.
There are probably several other solutions as well, but that was the first one that came to my mind.
Hope that helps.