1

am I right to say that an instance of a function object is immutable since there's no way we could modify a function once its created?

Anyway, to rephrase my question:

  var f1=function(){
        return true;
    }

    //Now i pass **f1** into the function **G**, storing it to **g1**
    function G(f){
    return function(){
            return f();
    }
    }
    var g1=G(f1);

    //I will try to hack/do anything i can to **f1**
    //Now i will pass f1 to hacked piece of injection code which (assumingly) will try to hack f1


    g1(); // but I can be 100% sure this will still return me true

So now can I be sure that no matter what I do to f1, g1() will Forever return me true ?

Despite being interested in browsers with at least 0.5% of the internet users market share: I welcome answers that goes along the lines of "in [x] browser this is not safe because.."

I am aware that since the code is run at the client, if the client has a malicious intent he will be able to do whatever he want.. But this question is specifically targeted at protecting "users who do not have malicious intents", in other words.. a normal user (if the user is a hacker than i don't mind letting him mess with the functions anyway he wants since he'd get all the exceptions thrown in his face and that's none of my business)

Pacerier
  • 86,231
  • 106
  • 366
  • 634
  • 1
    Do you mean the function *body* or the object's *properties*? – Jeremy May 26 '11 at 15:52
  • @Jeremy Heiler I've edited the question – Pacerier May 26 '11 at 16:15
  • 1
    Your code will error when calling `g1()` because `g1` is `true`. I think you meant to make the body of `G` be `return f;`. Either way, all you are doing is passing `f1` around, so, in this case, any changes to it will be reflected wherever it is. However, I don't think there's a legit way to change the function body after the function has been declared. It also depends on if you function references anything outside it. – Jeremy May 26 '11 at 16:25
  • @Jeremy Heiler nop, the function does not reference to anything outside. So basically we can be 100% sure the function body cannot be touched? – Pacerier May 27 '11 at 02:33
  • @Pacerier: The only way I know of is to completely swap out the function body with a new function. And since `g1` now contains a reference to the function in `f1`, swapping out the body of `f1` doesn't really matter. That's all I can say right now, I am certainly not qualified enough to say that I am 100% certain that nothing else can happen. And I don't want to be liable :-P – Jeremy May 27 '11 at 13:12
  • @Jeremy Heiler dang there was a serious typo mistake in the code previously which i've not noticed.. pls read the question agian thx! – Pacerier Jun 12 '11 at 15:16

2 Answers2

2

No:

var f = new Function("");
f.prop = 1;
Matthew Flaschen
  • 278,309
  • 50
  • 514
  • 539
1

You cannot stop the variable g1 from being reassigned on all browsers. Some browsers would allow you to define g1 as a constant thus:

const g1 = G(f1);

which would prevent the name g1 from being rebound, and you can use Object.defineProperty to define a read-only global property of window on others, but in general, there are no const definitions in JavaScript.

To make it clearer, consider two scenarios:

(1) An attacker can run code in the scope in which f1 is declared, and then other code reads f1.

var f1 = ...;   // You define f1
f1 = function () { return false; };  // Attacker code runs
doSomethingWith(f1());  // Naive code reads f1 and calls it.

The attacker succeeds in this case in confusing the naive code because they changed the value at f1.

(2) An attacker runs code in the scope after f1 has been read.

var f1 = ...;  // You define f1
// Cautious code reads and stores f1 in a safe place for later use.
(function () {
  var f = f1;
  setTimeout(0, function () { doSomethingWith(f()); });
})();
f1 = function () { return false; };  // Attacker code runs.

The attacker fails in this case because the cautious code read the value of f1 before the attacker changed the value stored at f1, so the private f continues to return true.

Community
  • 1
  • 1
Mike Samuel
  • 118,113
  • 30
  • 216
  • 245
  • serious typo in the code.. i've edited my question: it is not the code you assumed it to be.. but rather: `function G(f){return function(){return f;}}` – Pacerier Jun 12 '11 at 15:17
  • @Pacerier, removed bit about definition of G since it looks like your new definition of G will do what you want. The rest of the post, about how to make the name `g1` always point (modulo masking) to the same function instance is still relevant. – Mike Samuel Jun 12 '11 at 15:20
  • so even after i've passed the instance of the function called `f1` into an attacker's script, he can do whatever he want to `f1` but at the end of his script i can still call `f1` and say that it will 100% return me true? – Pacerier Jun 12 '11 at 15:37
  • @Pacerier, If `f1` is a local variable (not a global) in your script and you pass `f1` to an attacker's script, he can muck with it's properties, including changing the `call` and `apply` methods, but he cannot change what `f1()` means inside your script. If you are passing it across frame he can poison the prototype by assigning to `f1.prototype[propertyName]`. – Mike Samuel Jun 12 '11 at 15:49
  • and is it right to say that even if he did poison the prototype by assigning to `f1.prototype[propertyName]`, I will call `f1()` and it will still give me `true`? – Pacerier Jun 12 '11 at 15:57
  • 1
    @Pacerier, If you call `f1` via `f1()` and it either takes zero arguments or you do not call any arguments then it will still give you `true`. Obviously, if you define a function that calls one of its arguments `var h1 = function (f, x) { return f(x); }` and you pass it to an attacker, they can rename `h1` by doing `h1(eval, "h1=function () { ... }")`. You should always be suspicious of the value of `this` since an attacker can control that just as easily as any other parameter. – Mike Samuel Jun 12 '11 at 16:10
  • 1
    And you should be wary of storing secrets in the code of any function you pass to an attacker; you don't want `f.toString()` to return something like `function () { var privateKey = "..."; ... }`. – Mike Samuel Jun 12 '11 at 16:10