The post will be interesting to 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 specific certificate).
My team is developing an online service for payroll. We were faced with the task of signing the sent reports with the client's private key, therefore, it is necessary to execute a dangerous code from the browser’s point of view on the client’s machine. At the same time, I wanted very much not to limit the client in choosing a browser to use our service.
Here is how we solved this not very trivial task.
')
So, we need to run a fairly unsafe code on the client’s machine. Of course, just because no one will allow us to do this, but hope has not left us 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.
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 work in all these browsers.
The solution came pretty quickly. The idea is this: the user installs a small program on the machine that can perform the actions we need. The interaction with it can be done using HTTP requests. The program turned out really small, she was able to receive incoming requests of a special type and run the appropriate CryptoApi methods.
It remained to understand how to make the necessary request for 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. This means that 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 one performing the request and allowed us to do without HTTPS, on the other hand, this meant that we would have to make a cross-domain call, which in itself is associated with a number of problems. The subtleties of cross-domain calls have already been discussed at Habré, for example, in
this article . Armed in this way with a rich toolkit, we set about experimenting.
CORS
As a first approach, we decided to use the simplest of the available methods - Cross-Origin Resource Sharing. This technology is supported by many modern browsers and is easy to implement. But, unfortunately, it is not supported by Opera, and its implementation in IE makes it impossible to make local calls from sites in the categories Internet and Intranet. And if we could put up with the latter (we had our ActiveX component in stock), then we did not sacrifice support for the Opera. From the idea of writing an extension for the Opera, which would have proxied local calls from the necessary addresses, we were dissuaded by the interfaceologists - and we ourselves were not sure that all users would understand the installation of 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 on this path we were again awaited by security policies, this time the flash itself. We did not have time to rewrite our service to use only GET requests (to circumvent the ban on POST requests from https to http), as it turned out that flash applications obtained from the Internet and Intranet areas are placed in the sandbox isolated from the user's machine in including http requests. Again by.
Jsonp
Then a new idea struck us. The ability to do only GET requests meant that we could slightly modify the request format to use JSONP technology. Rule, run - works. But it is only in Chrome. Firefox is similar. But in the Opera and in IE we were once again waiting for problems. It turned out that the security policies of these browsers prohibit the connection of scripts located in a more private address zone. Agrrrh!
Iframe

The next experiment is to open the iframe on 127.0.0.1 and somehow communicate with it. And again, the safety of the Opera let us down. These properties of the security policies of the Opera threatened to put an end to our idea. It turned out that in case of a cross-domain access to the user's machine, including connecting scripts, redirect and opening in the iframe, Opera puts the service page opera: crossnetworkwarning in which the user can confirm his desire to switch to the local machine (of course, when downloading from the local machine, the user of this page will not see and will not be able to confirm anything). The only exception is when the user explicitly made the transition (for example, when clicking on a <a href="http://localhost/" target="my_frame"> link).
Iframe + PostMessage
It turns out that somehow, but iframe with a local address can be opened. But then you can communicate with the local server using postMessage! It remains only to choose how to open a local frame. There are actually two possibilities: either to show the user a link that will perform a transition to a local address in a hidden frame, or to perform a transition by himself and provide 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 permission for a specific domain, as a result, the user will only need to take extra action once. In addition, this method allows you to repeat the attempt to access the service without user intervention, in the case when it is not installed or not started, and to run the required method as soon as the service becomes available.
Total
postMessage does not work in IE 6-7 and in Firefox 3, but we decided not to add a-la hash-polling to this case. For IE users, we left the ActiveX component, and for Firefox 3 users (of which we have very few), we decided to offer to upgrade to later versions.
Well, a bit of PR (the project is good, so I hope for understanding). If your wife or mother is an accountant and includes hundreds of thousands of unhappy women who are calculating salary in a monster program, recommend them to see
Eureka (this is the name of our service). Enough already to suffer from all nepotrebschiny.