If you are a web developer you may have experienced that there are many situations that you need to access remote domains for data sources. For an example if you are building a weather mashup, you may like to connect to some weather forecasting services likeĀ  http://www.weather.gov or http://weather.cnn.com/weather/forecast.jsp. Mostly these services are very simple, so you can build these services from Javascript itself. (FYI you can use the blog post, I wrote sometime back, Calling Simple Web Services From Javascript.) But browsers doesn’t make it this much straight forward.

For an example if you try running the following code, which basically do a simple AJAX call to an external domain,

    // some external domain
    var url = "http://test.dimuthu.org";

    // doing the ajax call
    var req = new XMLHttpRequest();

    req.open("GET", url, true);
    req.onreadystatechange = function (e) {
        if (req.readyState == 4) {
            if(req.status == 200) {
                alert(req.responseText);
            }
        }
    }

    req.send(null);

You will get a security exception from the Firefox (opera too gives a similar exception).

uncaught exception: Access to restricted URI denied (NS_ERROR_DOM_BAD_URI)

In order to avoid this, you have do some special work.

  1. You need to add the following code before doing any AJAX request to external domains, This will give the script special privileges to access any domain through XMLHttpRequest object.
        try {
            netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
        } catch (e) {
            alert("Permission UniversalBrowserRead denied.");
        }
  2. If your script always jump to the exception, you have to configure your browser to allow the above setting. You can do this by going to the “about:config” page in Firefox (Just type the “about:config” in the url field and hit Enter) where it shows a list of configurations, there you need to set “signed.applets.codebase_principal_support” field to “true”. By default this field is set to false in Firefox 3.0

After you completed above 2 steps, the page will show you an warning message saying that it is asking more privileges, in which the client have to click the “allow” button to continue.

This procedure is not much difficult to setup, but still it will be really painful for an average user, so it is better you avoid this as much as possible in your code.

The main reason this special setup is arranged in Firefox (and most of the other browsers) is attackers can run malicious scripts in some page which you trust, (for an example from one of your email message) and send your private data to some other domain that you don’t know and don’t trust.

Apart from XMLHttpRequest another famous way of accessing different domains from a web page is using framesets or iframes. using this technique, You can show an external web page inside yours as it is one part of that.

Before Firefox 3.0 and IE 7.0 you were able to change that external page (appearance or the content) according to your need when it is shown in a frame or iframe. This was possible to do by manipulating the DOM of that external page. But with Firefox 3.0 and IE 7.0 it is impossible. That is you still you can show an external page inside your web page, but you can’t change anything of it even it shows inside your page. Because it doesn’t allow you to access the DOM of that external page. See this issue is discussed in details at here, https://bugzilla.mozilla.org/show_bug.cgi?id=397828

With this improvement, you can’t call the window.document if the page of the window is from external domain.

The reason to this limitation is apparent, if you ever thought of modifying external pages and put it in your web page, you will be able feel many security holes in there. You can show some web based email login page in one of iframe, and fool some users. If that web based email application is not changed by the iframe container, it won’t be a problem, but how it is changed to submit your username, password to the parent site by updating the submit event (onclick attribute) of the DOM of that external page.

In fact Firefox and most of the browsers are trying to protect your from all these security attacks by restricting lot of functionalities of the browsers. They are doing what they can do it in the client side, but you don’t know what exactly happens in the server side since it is always a black box. The all the restriction mentioned above (i.e. accessing remote services, changing and showing an external web page) can be done in very simple PHP or .NET code in server side. So it is right that you should use the right tools, but more important thing is you are aware of these attacks and you selectively browse web while avoiding them

Web services has made the communication between heterogeneous environments (say PHP with .NETĀ  or Java) a reality. It has defines standards for communicate not only with texts but also with binaries. And more importantly you can keep these communication confidential using encrypted messages according to your requirement. In this post, we will look at how we can implement such a system with PHP in one side.

In web services we can send/receive binary messages in two basic forms.

  1. Setting the binary inside the SOAP message. - Binary should be converted to base64 to make sure the SOAP body contains only texts. Since base64 converted data span longer than the binary data, we call this form as non-optimized way of sending binaries.
  2. Setting the binary outside the SOAP message - Binary would be sent as a MIME part in the message. And some element inside SOAP body keeps a reference to the binary using the MIME id. MTOM is a standard for referencing the MIME from inside the SOAP body. Since the binary is encoded, this will keep the message optimum with the binaries.

In WSF/PHP you can use any of these methods as you prefer. Lets forget about the encryption for now. We will check how we can send binaries in both of the above mentioned forms.

// first the request xml. Note tht xop:Include element that is referring the attachment with the id "myid1".
$reqPayloadString = <<<XML
<ns1:upload xmlns:ns1="http://wso2.org/wsfphp/samples/mtom">
               <ns1:fileName>test.jpg</ns1:fileName>
               <ns1:image xmlmime:contentType="image/jpeg" xmlns:xmlmime="http://www.w3.org/2004/06/xmlmime">
                  <xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:myid1"></xop:Include>
               </ns1:image>
</ns1:upload>
XML;

try {
    $f = file_get_contents("my_binary_file.jpg");

    // here in the attachments option we define the binaries
    // corresponding to the id defined in the above XML
    $reqMessage = new WSMessage($reqPayloadString,
                                array("to" => "http://localhost/simple_upload_service.php",
                                      "action" => "http://wso2.org/upload",
                                      "attachments" => array("myid1" => $f)));

    // creating the WSClient
    // here the option useMTOM will decide whether the
    // attachment is set MTOM or base64
    $client = new WSClient(array("useWSA" => TRUE,
                                 "useMTOM" => TRUE));

    // sending the message and retrieving the response
    $resMessage = $client->request($reqMessage);

    printf("Response = %s \\n", $resMessage->str);

} catch (Exception $e) {

    if ($e instanceof WSFault) {
        printf("Soap Fault: %s\\n", $e->Reason);
    } else {
        printf("Message = %s\\n",$e->getMessage());
    }
}

As mentioned in the inline comment we can choose the preferred form of sending binary using the “useMTOM” option. if it is true, the binary is set as a MTOM, (referencing from the body) or if it is set false, the binary will be set as a base64 binary within the SOAP body.
To encrypt the message you only need to write few additional lines. First you define your policy that you need to encrypt this message using a WSPolicy object. Then the security token including the service public key and your private key. You need to give these two option as a constructor argument in WSClient. Here is that little additional code you need to write to add the encryption.

    // loading the keys
    $rec_cert = ws_get_cert_from_file("receiving_server.cert");
    $pvt_key = ws_get_key_from_file("my_private_key.pem");

    // here we defines the policies and create WSPolicy object
    $sec_array = array("encrypt" => TRUE,
                       "algorithmSuite" => "Basic256Rsa15",
                       "securityTokenReference" => "IssuerSerial");

    $policy = new WSPolicy(array("security" => $sec_array));

    // defining Security Tokens
    $sec_token = new WSSecurityToken(array("privateKey" => $pvt_key,
                                           "receiverCertificate" => $rec_cert));

    // modifing WSClient with adding WSPolicy and WSSecurityToken object
    $client = new WSClient(array("useWSA" => TRUE,
                                 "useMTOM" => TRUE,
                                 "policy" => $policy,
                                 "securityToken" => $sec_token));

You can implement the receiving side of the message similar to the sending side that we just described above. The most important thing is it doesn’t need to be written in PHP. It can be a Java code or .NET code.If you already have web services that use encrypted binary messaging, the above php code can be use out of the box to communicate with it.