Cross-browser launch of "malicious" code on the client

    The post will be interesting for web developers interested in running unsafe code on the client (from the browser). By “malicious” we mean code that we cannot execute in pure JavaScript (in our case, signing a piece of data with a certain certificate).

    My team is developing an online service for calculating salaries. We were faced with the task of signing the reporting statements with the client’s private key, therefore, we need to execute code dangerous from the browser’s point of view on the client’s machine. At the same time, I really wanted to not limit the client in choosing a browser to use our service.

    This is how we solved this not the most trivial task.

    So, we need to run quite unsafe code on the client machine. Of course, nobody will let us do it just like that, but the hope that with a sufficient number of questions “Are you sure?” and "Do you trust this site?" our idea will pass.

    At the entrance, we had a working ActiveX library that did everything we needed, but only in IE. We needed a cross-browser solution.

    We’ll immediately make a reservation about our understanding of the term “cross-browser”. According to statistics, our users use the following browsers:



    IE 8+ (39%)
    Mozilla Firefox 3.6+ (19%)
    Opera 9+ (17%)
    Chrome (14%)
    IE 7 (6%)
    IE 6 (4%)
    Safari 5 + (1%)

    Accordingly, we needed correct operation in all these browsers.

    The solution came pretty quickly. The idea is this: the user installs a small program on the machine that could perform the actions we need. Interaction with it can be done using HTTP requests. The program turned out really small, she was able to accept incoming requests of a special kind and run the corresponding CryptoApi methods.

    It remained to understand how to make the necessary request to such a server. It was not possible to make such a request from the server - the user's machine may not have an external ip-address for a dozen different reasons. So, the request must be executed from javascript code to the address 127.0.0.1. On the one hand, this greatly facilitated the task of identifying the requestor and allowed to do without HTTPS, on the other hand, this meant that we would have to make a cross-domain call, which in itself was fraught with a number of problems. Subtleties of cross-domain calls were already discussed on Habré, for example, in this article . Armed in this way with rich tools, we set about experimenting.

    CORS


    As the first approach, we decided to use the simplest available method - Cross-Origin Resource Sharing. This technology is supported by many modern browsers and is easy to implement. But, unfortunately, it is not supported by the Opera, and its implementation in IE makes it impossible to make local calls from sites in the Internet and Intranet categories. And if we could still put up with the latter (we had our ActiveX component in stock), then we did not sacrifice Opera support. The idea of ​​writing an extension for Opera, which would proxy local calls from the right addresses, was discouraged by the interface experts - and we ourselves were not sure that all users would figure out how to install the extension. In addition, it would also have to be updated in a timely manner ... I had to look for other solutions.

    Flash


    Our next idea was to use the flXHR library for cross-domain queries . But along this path we were again lurking by security policies, this time flash itself. Before we had time to rewrite our service to use only GET requests (in order to circumvent the ban on POST requests from https to http), it turned out that flash applications received from the Internet and Intranet areas were placed in a sandbox isolated from the user's machine in including by http-requests. Again past.

    Jsonp


    Immediately a new idea dawned on us. The ability to get by with only GET requests meant that we could, by slightly adjusting the request format, use the JSONP technology. Edit, run - it works. But this is only in Chrome. Firefox - similarly. But in Opera and in IE we again had problems. It turned out that the security policies of these browsers prohibit the connection of scripts located in a more private address zone. Agrrrrh!

    Iframe




    The next experiment is to open the iframe at 127.0.0.1 and somehow communicate with it. And again, the safety of the Opera failed us. These properties of Opera's security policies threatened to put an end to our idea. It turned out that during cross-domain access to the user's machine, including connecting scripts, redirect and opening in iframes, Opera places an opera: crossnetworkwarning service page instead of a response, in which the user can confirm his desire to switch to the local machine (naturally, when loading the script from the local machine, the user of this page will not see and cannot confirm anything). The only exception is when the transition is explicitly made by the user (for example, when you click on a link ).

    Iframe + PostMessage


    It turns out that in no way, but iframes with a local address can be opened. But then you can also communicate with the local server through postMessage! It remains only to choose how to open the local frame. There are actually two possibilities: either show the user a link that will perform the transition to the local address in a hidden frame, or perform the transition on their own and allow the user to independently allow the transition. After hesitating, we chose the second path. Its advantage is that on the opera: crossnetworkwarning page (as can be seen in the screenshot), it is possible to remember the resolution for a specific domain, as a result, an extra action will be required from the user only once. In addition, this method allows you to retry trying to access the service without user intervention, in the case when it is not installed or is not running,

    Total


    postMessage does not work in IE 6-7 and Firefox 3, but we decided not to add a-la hash-polling crutches for this case. For IE users, we left the ActiveX component, and for Firefox 3 users (of whom we have only a few), we decided to offer to upgrade to later versions.

    Well, a little PR (the project is good, so I hope for understanding). If your wife or mother is an accountant and is one of the hundreds of thousands of unhappy women who are calculating salaries in a monster program, recommend them to see
    Eureka (as our service is called). Enough already to suffer from all non-consumerism.

    Also popular now: