Differentiating between parsing functions stored as strings in object literals/JSON syntax involves identifying each function's unique characteristics

While there is a similar question (here), the answers provided do not exactly address my query. The accepted answer included invalid JSON (forcing the use of eval()), which seems to be an impossible solution as far as I know.

I intend to utilize code from my own server, stored in string format using object literal syntax, but I also wish to incorporate functions within it.

My current train of thought involves these possibilities:

  1. Directly applying eval() to parse the string
  2. Enclosing functions in string format (possibly with something like "\bfunction" for identification), then utilizing JSON.parse() followed by a for-in loop to check if any functions need parsing (which might be slow)
  3. Utilizing the DOM to execute the code through a <script> tag and running it there

The code will not contain any user-editable content, but I am unsure if there could be a safety concern or simply a performance issue. Is the use of eval() suitable in my scenario, and are there more efficient methods other than manually searching for functions or resorting to eval()?

EDIT: Would opting for an alternative syntax for parsing be a better approach, or would it just add further complexity?

EDIT2: My goal is to achieve something along the lines of the following:

{ "test": function () {}
, "foo": 1
, "bar": 2 }

I am not aiming to solely parse an entire function from a string, for example:

eval('function(){}');

Answer №1

Effectiveness: Will they perform as expected?

All options 1, 2, and 3 are viable.

  1. Evaluate the responseText: This method works well. However, if you implement a same-origin challenge as per security recommendation #3, you must address it first.

  2. Identify individual items in the object to "revive". I have used this approach before and prefer using a naming convention for keys to determine when to revive rather than a marker in the value. Refer to MDN documentation on JSON.parse for more information on revivers.

    In both cases 1 and 2, you need to find a way to parse and execute the function text. Here are your choices, none of which are entirely risk-free (refer to the security section).

    If you use f=eval(responseText), this is a "direct eval." The function will have local scope where eval is called.

    If you use f=(1,eval)(responseText), this is an "indirect eval." The function will have global scope. Check out this article for more details on global eval.

    If you use f=new Function(responseText), the function will have a separate local scope within the global scope.

  3. This technique is known as JSONP (JSON with padding). It's effective and probably the easiest to implement. However, it is not recommended if the response may contain sensitive user data (see below).

Security: Will they avoid unauthorized actions?

If you can ensure that the delivered message is under your control (100% confident no user or attacker can tamper with it): Options 1, 2, and 3 do not compromise the user's browser state (e.g., XSS, allowing access to sensitive cookies).

If the delivered message might not be completely under your control: Methods 1, 2, and 3 pose risks to the user's browser state and are unsafe. Consider these alternatives:

  • Accept the security risk (users/attackers can manipulate your site functionality, potentially stealing user cookies, accessing sensitive information, etc.)

  • Pass potentially unsafe functions to a web worker for sandboxed execution. Note that this requires additional effort and may not be supported by all browsers.

  • Execute potentially risky functions in an iframe on a different domain to protect user data but still vulnerable to attacks redirecting users to malicious sites. Trust in secure browser settings for protection.

  • Utilize whitelisted functions that you control and pass only authorized function names around.

If you transmit user-specific information within your data:

  • Option 3 is not suitable for handling sensitive user data (as the script could be called with the user's cookies from any domain) unless your server implements strict checks on referer/origin HTTP headers. Even then, there may be vulnerabilities. Learn more about XSRF here.

  • Naive implementations of options 1 and 2 also come with XSRF risks where malicious sites can forge requests using user cookies. Take precautions like adding syntax errors or loops that would break the script if interpreted incorrectly by a cross-domain script attempting to read the content.

  • To make options 1 and 2 XSRF-safe, introduce statements that would cause failure if interpreted as a script, such as invalid syntax or infinite loops, then adjust the received text to eliminate those errors. Same-domain scripts can access and modify responseText before parsing, unlike cross-domain scripts that require script tag insertion for access.

Answer №2

When it comes to bringing function code to the client, you have a couple of options:

  • One option is to use a JavaScript object literal that includes function expressions. You can implement this using AJAX and eval, or take a JSONP-like approach with a <script> node. Both methods have their benefits, but AJAX offers more flexibility in terms of HTTP methods and synchronous requests, without requiring a global callback function.

    Using a JavaScript expression provides you with complete freedom, allowing for custom data types (such as Date objects or your own constructors) and even circular structures (when wrapped in an IEFE). However, serializing this data on the server into a script can be challenging and error-prone, requiring careful crafting to avoid syntax or runtime errors that could cause parsing failures.

  • Another option is to use valid JSON and then create functions from known code strings. By sticking to this standardized format, serverside serialization becomes simpler and the data becomes accessible to clients without a need for a JS interpreter. This method is widely used by those familiar with working with objects featuring custom prototypes, utilizing the Function constructor.

    Depending on your schema, you can either manipulate the parsed structure directly to redefine properties, or utilize the reviver callback argument in JSON.parse. Here's an example:

    var json = '{"validators":[{"name":"required", "message":"must be filled", "fn":["str", "return str.trim().length > 0;"]}, {…}, …]}';
    var result = JSON.parse(json, function(k, v) {
        if (k != "fn") return v;
        return Function.apply(null, v);
    });
    

Answer №3

There are multiple methods to generate a JavaScript function from a string, however relying on eval is considered harmful and best avoided whenever feasible.

You have various alternatives for creating the function, such as utilizing the new Function("...") syntax, or defining a function within your scope and then invoking it with arguments as strings. I have conducted a test in JSFiddle to demonstrate this process. Although eval may be the quickest approach, it is not recommended. Both the DOM method and using new Function() exhibit similar speeds, differing by only a few milliseconds after 1000 iterations (fn: 3328, DOM: 3371). Feel free to explore the results for yourself by accessing the JSFiddle link.

The primary distinction between eval and new Function is that the former has access to local variables while the latter does not. For more details, refer to this informative Stack Overflow answer.

Answer №4

There are limited choices available to you, however a potential fourth option (commonly utilized by JQuery) is as follows:

var customFunction = new Function("var b=2; return b; //here lies the logic of your function");

Answer №5

For your specific scenario, there are a few key points to take into account.

In my opinion, when it comes to using eval, if you find yourself unsure, it's probably best to avoid it altogether. Some individuals get caught up in optimizing performance to the smallest degree, but is the difference between 100,000ops/sec and 1,000,000ops/sec truly going to impact the usability of your application significantly? Moreover, considering that not all browsers support JSON natively, compatibility also becomes a crucial factor.

With that being said, my initial suggestion would be:

If JSON needs to transmit these functions (which seems somewhat unusual) and you have control over the server data, one approach could be to prefix your functions with something like js-. If immediate execution upon reception is required, you can remove the prefix using substr and trigger them using bracket notation as shown below:

// Iterate over values
if (value[i].substr && value[i].indexOf('js-') === 0) {
    var func = value[i].substr(3);

    // Assuming it's a globally accessible function
    window[func]();
}

If delayed execution is more appropriate, consider storing them in an array or object literal for later invocation.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

extracting data from parse

While I have successfully retrieved information about the current user using Parse, my goal now is to retrieve data from a different user, identified by their objectID. For example, here's how I currently fetch and display information about the logged ...

Varied elevations dependent on specific screen dimensions

There seems to be a minor issue with the height of the portfolio container divs at specific window widths. The problematic widths range from 1025 to 1041 and from 768 to 784. To visualize this, try resizing your browser window to these dimensions on the fo ...

conceal elements using the <option> class隐藏

Although it seems like a simple task, I'm struggling to make it work. I created a form where the user can select a month from a list using the tags: <select> <option> When the selection is changed, the class .gone from the day SELECT is ...

Steps to adding a collection of links (stylesheets, javascript files) to each html document

Is it feasible to add a list of links to multiple HTML files? I was inspired by W3 School's W3 Include functionality, which allows you to import blocks of HTML code into various files simultaneously, making it convenient for making changes across many ...

Dynamic Bootstrap Tab menu slider with movable functionality when the limit is reached

I am facing an issue with the tabs menu on my website. The tabs menu items can vary between 2 or 3 to even 20 or more. When the number of navigation items exceeds 10, they automatically drop to the second line, which you can see here. However, I don' ...

What is the most effective way to implement a global notifications feature?

I'm working on developing my mobile API using Node.js and I am unsure about the best approach to store my notifications functions. These functions are being called multiple times in my code and I am undecided whether to use a global function, class, o ...

Looking to access a .doc file stored on your SD card within your Android application?

I am in need of a solution to view .doc files within an android app. After researching various related posts, I am still unsure of the best approach. Here are the methods I have attempted: Using the Aspose Word API for Android allowed me to create .do ...

React application experiences CORS issue due to lack of 'Access-Control-Allow-Origin' header when integrating with Facebook platform

As a junior developer who is relatively new to utilizing Facebook for Developers, I am encountering a challenge with the ReactJs application that I am currently working on. I could really use some assistance! My boss has specifically asked for a Grid repr ...

How do I retrieve the value of a class that is repeated multiple times?

In the HTML code I am working with, there are values structured like this: <div class="item" onClick="getcoordinates()"> <div class="coordinate"> 0.1, 0.3 </div> </div> <div class="item" onClick="getcoordinates() ...

Tips for creating a vertical Angular Material slider with CSS

Attempting to modify the angular material directive to render vertically has been a challenge. I experimented with using transform:rotate in the CSS, however, it resulted in the slider behaving and rendering differently. md-slider { position: absolute ...

The concatenation of Ajax results appears to append to the existing data

My ajax function handles uploading comments to a form, which then returns the same string. If successful, the comment is added to a comment box and the input text is cleared. The issue arises when a user adds another comment; the new comment is appended w ...

Strategies for detecting and handling blank data in JSON parsing with JavaScript

Here is a function that retrieves details: function GetSomeDetails(Param) { Json_Parameters = JSON.stringify(Param); $.ajax({ type: "POST", url: "MainPage.aspx/MyMethod", data: J ...

What are the best methods for testing REST API and Client-side MVC applications?

When dealing with a RESTful server that only responds with JSON data fetched from a database, and having a client-side application like Backbone, Ember or Angular, where should application testing take place? Is it necessary to have two sets of tests - on ...

A step-by-step guide on integrating vuetify-component into codeceptjs

When attempting to write tests using codecept.js, I am facing difficulties accessing the vuetify components. <v-layout> <v-flex xs7> <v-text-field ref="video1min" v-model="video1min" :rules=" ...

What sets Express.js apart from koa2.js in handling asynchronous functions?

I've encountered a situation where I had to set up the router using Express, and it was functioning correctly with the following code: router.get('/',(req,res)=>{ queries.getAll().then(stickers=>{ res.json(stickers) }) ...

The anticipation of a promise: fulfilling responsibilities versus just waiting

When utilizing an await Promise with assignment compared to using await without assigning the result, there are differences in behavior. Consider the example code below: const getSomething = async () => { let todos = null; await fetch('http://j ...

Steps to show an input button and exit the current window

I am looking for guidance on how to enable or display an input on a webpage if an ajax call is successful. I want this input, when clicked, to be able to close the current window using JavaScript. What would be the most efficient way to accomplish this? B ...

One way to display the contents of a div after the CSS has finished loading

Here is the code snippet that I am currently working with: $.ajax({ type: 'GET', url: 'url.php', success: function(data){ $("div#mainclass").hide().html(data).fadeIn(100); } }); After implementing this code, I ...

Parsing JSON data results in a string output

After realizing that my initial post was not clear enough, here are more details. Jade: meta(name='revObj', content=(JSON.stringify('#{rev[1]}'))) The resulting HTML from Jade: <meta name="revObj" content=""{ companyAddress: &apo ...

Mishandling of string interpretation

I'm having trouble converting ANSI color codes from console output into HTML. While I discovered a script that can handle this task, I am struggling to make it parse the strings within node js properly. Even when I attempted to JSON.stringify it to in ...