We wanted to share some of our thinking that led to enhancements in protocol design, which is now shipping in the latest version of the BitGo SDK. This post focuses on aspects of the SDK that enhance web traffic protection and validation, improving communication security for our customers.
One of the biggest problems with web applications is content integrity checks. As there is no simple way to verify content authenticity, most sites defer to using HTTPS, which is a good start towards encrypting and signing traffic. However, HTTPS does stream integrity checks at the transport layer, rather than at the application layer. Thus, the channel ends up being encrypted, but the application content integrity is not validated. Considering that obtaining a trusted certificate is very cheap, neither the encryption nor the signing HTTPS provides is sufficient.
A Mac running Sierra 10.12.2 has 169 trusted root certificate authorities.
As shown in the picture above, there are 169 trusted root certificate authorities on a typical Mac. Getting just one of them to issue a certificate is sufficient for a hacker to execute a completely undetected man-in-the-middle attack. In a scenario with untrusted networks, anybody could be doing a certificate replacement, particularly in public open networks like at a Starbucks or in a hotel room. Further, service providers may deliberately be subjecting their traffic to man-in-the-middle-attacks using automated SSL service providers such as Cloudflare. With these considerations in mind, the reassuring green lock in the browser bar may in fact be deceptive and lull people into a false sense of security.
The best solution is certificate pinning, but in an environment wherein both the certificate and the data are transmitted over the same channel, such a solution can never be optimal. The security mechanism that comes closest is HSTS, which BitGo has been using for years, but which relies on browser support and therefore provides only marginal utility to those of our users who use the BitGo SDK or BitGo Express rather than our web interface.
To fix that, we have been working on a public key pinning mechanism that is more reliable and works both within and outside browsers, making sure that all our customers are equally well-protected. It allows both server and client to verify each other’s requests and responses against a fixed key pair whose public key is embedded in the BitGo SDK, and it prevents access tokens from ever being sent across the wire explicitly.
The mechanism relies on ECDH and HMACs. When a user logs in, the server encrypts the new access token with a symmetric ECDH key calculated based on the user’s public key and server’s private key. To decrypt the access token, the client calculates the same symmetric key with the public and private roles reversed. The picture below shows an example login server response.
A browser network inspector showing a response from www.bitgo.com.
All authenticated API calls and responses, including the initial authentication response, attach an HMAC header of the transmitted data using the access token as the HMAC key. For subsequent authenticated calls, only the access token’s hash is ever transmitted over the wire in plain form. An additional benefit of this protocol is that even if somebody were to eavesdrop on the connection, due to the fact that the HMAC changes with every request, they would not be able to fake authenticated calls. Additionally, the Auth-Timestamp request header prevents replay attacks.
Request headers sent on an authenticated request to www.bitgo.com.
The response HMAC header (pictured below) allows clients to validate that the data transmitted from BitGo has not been modified. The HMAC and Timestamp headers can be seen in any common browser network inspector.
Response headers from www.bitgo.com to authenticated requests.
In contrast, one need look no further than any popular banking website or social networking platform, and see that for most sites, the authentication mechanism is static cookies. Writing this blog post, I did not deem showing the raw cookie information safe, which is why in contrast to the screenshots of the BitGo request streams, I blacked out parts of the picture below.
Request headers sent on an authenticated request to a popular website.
We at BitGo feel that this new protocol is an essential security feature, and urge all of our customers to take advantage of it. To use this new authentication mechanism, simply update your clients (BitGoJS) to their most recent versions. If you are using our web client or the BitGo Chrome extension, you are already being secured by this feature. If you are an existing API customer, your existing long-lived tokens will continue working; however, we do recommend that you generate new long-lived tokens and update your BitGo SDK to take advantage of the additional safety measures.
Going forward, we will continue to improve the communication protocols used at BitGo. While HTTPS is sufficient for many sites, we believe this additional layer of protection will prove critical for BitGo customers in the coming years. We look forward to helping others, including the Internet at large, adopting similar improvements for all web communications.