Perform URL rewriting in javascript methods that make HTTP requests of their own(javascript:open, XMLHTTPRequet.open, etc.)
Method
Overriding native Javascript methods with our own versions that perform URL rewriting prior to making HTTP request.
Theory
It is impossible to recognize wrapped or obfuscated Javascript methods and arguments without parsing the code with a
Javascript engine. Since writing a good Javascript engine and performing parsing of all event driven methods found in the
HTML document is out of scope of this project we will try to make the client browser's JS engine do the job.
Consider the following piece.
Code:
<script>
/*This method will be overridden*/
function foo(yourname)
{
alert('Hello ' + yourname);
}
Next time we call foo('John') in our code we'll see "(override) Hello John" popup.
Now, we need to keep a reference to the original method somehow, because we do not want to override the method completely, just add some URL
rewriting routine.
Code:
<script>
/*This method will be overridden*/
function foo(url)
{
alert('The URL is '+url);
}
/*keeping the reference to the original foo as base_foo*/
var base_foo = foo;
/*New method that overrides foo()*/
foo = function(url)
{
var new_url = psiphon_rewrite(url);
base_foo(url);
}
</script>
Practice
We've tried this approach with the following websites:
www.youtube.com(upload a video functionality)
it uses a lot of AJAX techniques so it was a good candidate. The XMLHTTPRequest(XHR) was wrapped using
ideas from XMLHTTPRequest.js project. We were able to upload files but the page would show 'Unknown upload errors'.
ozodlik.org(general JS functionality)
We couldn't get search button to work.
Problems analysis
In case of youtube.com some XHRs return responses that are used to dynamically change InnerHTML or other properties of
DOM elements. Sometimes these properties are URLs(divs dynamically changed to imgs).
Further debugging showed dynamic attachment of
JS events to DOM elements via XHR, such as "onload". Combination of the two produced the error described above as the dynamic image couldn't load causing
"onload" event to never fire.
The ozodlik.org showed a different kind of problem which is a 'document.location' object. In theory location.href is a property of location object, but changing it
causes document to reload with the new URL.
As we can see there is no method here so it is not clear how to intercept the URL in such a construct if possible at all.
Another potential problem is to recognize and prevent re-wrapping overridden methods by the document itself as it may use something like XMLHTTPRequest.js to wrap
native XMLHTTPRequest for example.
Code:
<script>
/*This method will be overridden*/
function foo(url)
{
alert('The URL is '+url);
}
/*keeping the reference to the original foo as base_foo*/
var base_foo = foo;
/*New method that overrides foo()*/
foo = function(url)
{
var new_url = psiphon_rewrite(url);
base_foo(url);
}
/*Yet another method that overrides foo()*/
foo = function(url)
{
dosomething_else();
}
</script>
Conclusion: this approach is a possible but far from full solution in javascript white-listing.
function werapping approach report:
Javascript "whitelisting" in psiphon
Goal
Perform URL rewriting in javascript methods that make HTTP requests of their own(javascript: open, XMLHTTPRequet.open, etc.)
Method
Overriding native Javascript methods with our own versions that perform URL rewriting prior to making HTTP request.
Theory
It is impossible to recognize wrapped or obfuscated Javascript methods and arguments without parsing the code with a
Javascript engine. Since writing a good Javascript engine and performing parsing of all event driven methods found in the
HTML document is out of scope of this project we will try to make the client browser's JS engine do the job.
Consider the following piece.
Code:
<script>
/*This method will be overridden*/
function foo(yourname)
{
alert('Hello ' + yourname);
}
/*New method that overrides foo()*/ '(overide) Hello ' + yourname);
foo = function(yourname)
{
alert(
}
</script>
Next time we call foo('John') in our code we'll see "(override) Hello John" popup.
Now, we need to keep a reference to the original method somehow, because we do not want to override the method completely, just add some URL
rewriting routine.
Code:
<script>
/*This method will be overridden*/
function foo(url)
{
alert('The URL is '+url);
}
/*keeping the reference to the original foo as base_foo*/
var base_foo = foo;
/*New method that overrides foo()*/ rewrite( url);
foo = function(url)
{
var new_url = psiphon_
base_foo(url);
}
</script>
Practice
We've tried this approach with the following websites:
www.youtube. com(upload a video functionality)
it uses a lot of AJAX techniques so it was a good candidate. The XMLHTTPRequest(XHR) was wrapped using
ideas from XMLHTTPRequest.js project. We were able to upload files but the page would show 'Unknown upload errors'.
ozodlik.org(general JS functionality)
We couldn't get search button to work.
Problems analysis
In case of youtube.com some XHRs return responses that are used to dynamically change InnerHTML or other properties of
DOM elements. Sometimes these properties are URLs(divs dynamically changed to imgs).
Further debugging showed dynamic attachment of
JS events to DOM elements via XHR, such as "onload". Combination of the two produced the error described above as the dynamic image couldn't load causing
"onload" event to never fire.
Code:
<script> onreadystatecha nge=function( )
if(xmlHttp. readyState= =4) getElementById( "imgholder" ); createElement( 'img');
img. onload = function (e) {
dosomething_ onload( );
img. onerror = function(e) {
report_ error(e) ; responseText;
imgholder. appendChild( img);
.............
xmlHttp.
{
{
var imgholder = document.
var img = document.
}
}
img.src = xmlHttp.
}
}
.........
</script>
The ozodlik.org showed a different kind of problem which is a 'document.location' object. In theory location.href is a property of location object, but changing it
causes document to reload with the new URL.
Code:
<input id="keywords0_" name="keywords0_" onkeypress="if (event.keyCode == 13) {location.href ='/search/?k=' + encodeURI( this.value) ;return false;}"...
As we can see there is no method here so it is not clear how to intercept the URL in such a construct if possible at all.
Another potential problem is to recognize and prevent re-wrapping overridden methods by the document itself as it may use something like XMLHTTPRequest.js to wrap
native XMLHTTPRequest for example.
Code:
<script>
/*This method will be overridden*/
function foo(url)
{
alert('The URL is '+url);
}
/*keeping the reference to the original foo as base_foo*/
var base_foo = foo;
/*New method that overrides foo()*/ rewrite( url);
foo = function(url)
{
var new_url = psiphon_
base_foo(url);
}
/*Yet another method that overrides foo()*/ _else() ;
foo = function(url)
{
dosomething
}
</script>
Conclusion: this approach is a possible but far from full solution in javascript white-listing.