Location hack: Difference between revisions

From GreaseSpot Wiki
Jump to navigationJump to search
(,)
mNo edit summary
Line 1: Line 1:
,
The '''location hack''' is an ugly but useful way to interact with the content scope of the page being [[user script]]ed. It does this by indirectly [http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Functions:eval evaling] strings within that scope.
 
== Background ==
 
For [[security]] reasons, [[Greasemonkey]] uses [[XPCNativeWrapper]]s and a[[sandbox]] to isolate user scripts from the web page.
Under this system, the user script can access and manipulate the page using event listeners, the DOM API, and [[API reference|GM_* functions]].
 
Sometimes the sandbox is too limiting, in which case the user script can access other parts of the page using [[unsafeWindow]].
As the name ''unsafe''Window implies, this can often be unsafe, and expose security holes.
 
In December 2005, Jesse Ruderman [http://www.squarefree.com/2005/12/01/updated-greasemonkey-scripts/ came up with the location hack], to be an alternative to unsafeWindow in many cases.
 
== Basic usage: page functions ==
 
Suppose the page contains a function called <code>pageFunc</code>, or <code>window.pageFunc</code>.
The user script knows this function as <code>unsafeWindow.pageFunc</code>.
 
The user script could simply call <code>unsafeWindow.pageFunc()</code>, but this can leak the sandbox.
Instead, the user script can take advantage of <code>javascript:</code> URLs, which always run in the content scope.
Just entering this URL into the browser's location bar does not leak a GreaseMonkey sandbox:
 
javascript:pageFunc();void(0)
 
A user script can programmaticaly navigate to this URL, to safely call the function:
 
location.assign( "javascript:pageFunc();void(0)" );
 
That, in a nutshell, is the location hack!
Essentially, it is wrapping a [[wikipedia:bookmarklet|bookmarklet]] into a user script.
 
It's important to add the <code>javascript:</code> scheme to the front, to turn it into a URL, and the <code>;void(0)</code> to the end, which keeps the browser from actually navigating to this URL after it is run.
 
== Modifying the page ==
 
The location hack can do anything a page script or bookmarklet can do, so it can modify content variables and such as easily as it can access them. For example:
 
location.href = "javascript:void(window.someVariable = 'someValue')";
 
== Executing large blocks of code ==
 
Executing more than one statement can become unreadable very easily. Luckily, JavaScript can convert functions to strings, so you can use:
 
location.href = "javascript:(" + function() {
  // do something
} + ")()";
 
Even though the function is defined in the sandbox, it is not a closure of the sandbox scope. It is converted to a string and then back to a function in page scope. It cannot access anything in the sandbox scope, which is a limitation, but is also essential to making this technique secure.
 
== Percent encoding issue ==
 
Sometimes percent-encoding the percent symbol is required. For example,
 
location.href = ("javascript:(" + function() {
  var n = 44;
  if(!('''n%22''')) alert('n is a multiple of 22');
} + ")()");
 
The above code will cause error because %22 is interpreted as double quotation mark. The workaround is:
 
location.href = "javascript:(" + encodeURI(
  function() {
  var n = 44;
  if(!(n%22)) alert('n is a multiple of 22');
  }) + ")()";
 
See also [http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Functions:encodeURI encodeURI()].
 
== Returning values ==
 
The location hack is really handy for passing values to the content scope, or to call functions defined there.
It is not, however, capable of directly reading a variable or value returned from a function.
Furthermore, it is run asynchronously, much like <code>setTimeout()</code>, so you cannot immediately rely on side effects.
(If you use the location hack to, for example, store a value in the DOM and then attempt to read it, it will only be available at some other later point in time.)
For reading javascript values from the content scope inside the sandbox, see [[Reading Content Globals]] for a reliable example.
 
== See Also ==
 
* [[Reading Content Globals]]
* [[Content Script Injection]]
 
[[Category:Coding Tips:Interacting With The Page]]

Revision as of 13:19, 30 September 2011

The location hack is an ugly but useful way to interact with the content scope of the page being user scripted. It does this by indirectly evaling strings within that scope.

Background

For security reasons, Greasemonkey uses XPCNativeWrappers and asandbox to isolate user scripts from the web page. Under this system, the user script can access and manipulate the page using event listeners, the DOM API, and GM_* functions.

Sometimes the sandbox is too limiting, in which case the user script can access other parts of the page using unsafeWindow. As the name unsafeWindow implies, this can often be unsafe, and expose security holes.

In December 2005, Jesse Ruderman came up with the location hack, to be an alternative to unsafeWindow in many cases.

Basic usage: page functions

Suppose the page contains a function called pageFunc, or window.pageFunc. The user script knows this function as unsafeWindow.pageFunc.

The user script could simply call unsafeWindow.pageFunc(), but this can leak the sandbox. Instead, the user script can take advantage of javascript: URLs, which always run in the content scope. Just entering this URL into the browser's location bar does not leak a GreaseMonkey sandbox:

javascript:pageFunc();void(0)

A user script can programmaticaly navigate to this URL, to safely call the function:

location.assign( "javascript:pageFunc();void(0)" );

That, in a nutshell, is the location hack! Essentially, it is wrapping a bookmarklet into a user script.

It's important to add the javascript: scheme to the front, to turn it into a URL, and the ;void(0) to the end, which keeps the browser from actually navigating to this URL after it is run.

Modifying the page

The location hack can do anything a page script or bookmarklet can do, so it can modify content variables and such as easily as it can access them. For example:

location.href = "javascript:void(window.someVariable = 'someValue')";

Executing large blocks of code

Executing more than one statement can become unreadable very easily. Luckily, JavaScript can convert functions to strings, so you can use:

location.href = "javascript:(" + function() {
  // do something
} + ")()";

Even though the function is defined in the sandbox, it is not a closure of the sandbox scope. It is converted to a string and then back to a function in page scope. It cannot access anything in the sandbox scope, which is a limitation, but is also essential to making this technique secure.

Percent encoding issue

Sometimes percent-encoding the percent symbol is required. For example,

location.href = ("javascript:(" + function() {
  var n = 44;
  if(!(n%22)) alert('n is a multiple of 22');
} + ")()");

The above code will cause error because %22 is interpreted as double quotation mark. The workaround is:

location.href = "javascript:(" + encodeURI(
 function() {
  var n = 44;
  if(!(n%22)) alert('n is a multiple of 22');
 }) + ")()";

See also encodeURI().

Returning values

The location hack is really handy for passing values to the content scope, or to call functions defined there. It is not, however, capable of directly reading a variable or value returned from a function. Furthermore, it is run asynchronously, much like setTimeout(), so you cannot immediately rely on side effects. (If you use the location hack to, for example, store a value in the DOM and then attempt to read it, it will only be available at some other later point in time.) For reading javascript values from the content scope inside the sandbox, see Reading Content Globals for a reliable example.

See Also