Web3js – Best Practices for Serving a DApp Over HTTPS and Connecting Using JSON RPC

dapp-developmentweb3js

Summary: we're serving an Ethereum DApp from a webserver through HTTPS. The DApp connects to an Ethereum node through JSON RPC using web3.js, which uses HTTP (not HTTPS). How to deal with this in a good way?

It's good practice to serve web content over HTTPS, so our app is served from e.g. https://myhost/. Browsers enforce the HTTPS practice to such an extent that when a site/app is served over HTTPS, the browser requires that any further connections made by the app (including XMLHTTPRequests as done by web3.js) are also loaded over HTTPS.

Hence when the app is served over HTTPS, the browser blocks the calls to the Ethereum node (which are always HTTP) because of a "mixed content" error. Tested this on latest Chrome/Windows, but I imagine other browsers would give the same result. Basically it's a good thing that the browser does this.

As far as I know, the current Ethereum implementations have no functionality for serving the JSON RPC endpoint through HTTPS. Hence it could be worked around by wrapping the JSON RPC connection in HTTPS, e.g. by creating a small Node.js service.

What I want to know is how do others deal with this situation, and is there perhaps a simpler solution than the suggested workaround that I overlooked?

Example "Mixed content" error message:

Mixed Content: The page at 'https://myhost/user/login' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://blockchain:8101/'. This request has been blocked; the content must be served over HTTPS.
HttpProvider.send @ httpprovider.js:77
finishedWithRewrite @ hooked-web3-provider.js:72
rewritePayloads @ hooked-web3-provider.js:107
next @ hooked-web3-provider.js:117
rewritePayloads @ hooked-web3-provider.js:122
send @ hooked-web3-provider.js:75
RequestManager.send @ requestmanager.js:73
Method.send @ method.js:168
SolidityFunction.call @ function.js:112
SolidityFunction.execute @ function.js:212
(anonymous function) @ VM6322:2
InjectedScript._evaluateOn @ VM6122:875
InjectedScript._evaluateAndWrap @ VM6122:808
InjectedScript.evaluate @ VM6122:664

To web3.js this presents itself as a connection error:

Uncaught Error: CONNECTION ERROR: Couldn't connect to node http://blockchain:8101, is it running?
at Object.module.exports.InvalidConnection (https://myhost/vendors/web3/dist/web3.js:3051:16)
at HookedWeb3Provider.HttpProvider.send (https://myhost/vendors/web3/dist/web3.js:4119:22)
at finishedWithRewrite (https://myhost/js/lib/hooked-web3-provider.js:72:91)
at HookedWeb3Provider.rewritePayloads (https://myhost/js/lib/hooked-web3-provider.js:107:18)
at next (https://myhost/js/lib/hooked-web3-provider.js:117:25)
at HookedWeb3Provider.rewritePayloads (https://myhost/js/lib/hooked-web3-provider.js:122:18)
at HookedWeb3Provider.send (https://myhost/js/lib/hooked-web3-provider.js:75:21)
at RequestManager.send (https://myhost/vendors/web3/dist/web3.js:5757:32)
at Method.send (https://myhost/vendors/web3/dist/web3.js:4898:59)
at SolidityFunction.call (https://myhost/vendors/web3/dist/web3.js:3915:31)

Note that I'm using a HookedWeb3Provider, but as the way the web3.js connects to the node is identical I don't expect that to make any difference.

Currently using web3.js 0.13.0.

Best Answer

The answer is you don't. Now I know you probably don't want to hear this but the HTTP JSON RPC was never meant to be used in such a way that it should be accessible from the outside. The RPC was brought in to existence so that you may develop against your own local node using your own browser.

What I suggest you do is that you setup a proxy that will proxy all requests to the locally running ethereum node instead of letting everyone directly interface with the ethereum node itself. This will give you controlled access and HTTPS.