Cryptography-backed digital identities
Digital identities on Bitrated are backed by a public/private key pair. Every user has a public SIN identifier attached to them (representing their public key), and a matching private key that's managed locally by the user.
We use digital signatures to authenticate actions made by users, such as agreeing to a contract, posting a review or updating the profile. The digital signatures are then made available as part of our API.
Our usage of cryptography achieves three primary goals:
Authenticity - it shows that the data is authentic, unmodified and originating from the claimed author, even when published outside of Bitrated (e.g. on a peer-to-peer decentralized network).
Data Integrity - it ensures the accuracy and consistency of the data and prevents unauthorized modifications by a third party. This means that even if Bitrated's servers get compromised and provide forged data, users are still able to detect it and are not required to blindly trust our servers.
Non-Repudiation - it allows proving to any interested party that a user made certain actions or statements, helps establish the real historical timeline and makes it difficult for users to deny their past actions.
Client-side handling of private keys
The Bitrated web interface provides digital identity and smart contracts management using in-browser cryptography. Private keys are fully created, managed and processed using client-side code, and never touch our servers (not even in encrypted/hashed form).
This puts the full control over your identity and funds in your hands – where it belongs.
Protected client-side environment
Since private keys are managed in-browser and are accessible to client-side scripts, we take great care to protecting the integrity of our client-side environment:
Connections to Bitrated are always encrypted with SSL, the industry standard for encrypting web communications. In addition, we:
- Use Strict-Transport-Security to instruct browsers to always connect over SSL,
- Support perfect forward secrecy to ensure that even if our keys get compromised in the future, our past communications remain secured.
- Carefully select our supported ciphers and prevent downgrade attacks.
All scripts are served directly from our web server. We don't use CDNs, never embed external scripts and don't have any third-party trackers or analytics services.
We use a strict Content-Security-Policy that instructs browsers to prevent inline/external scripts from being evaluated under the context of our domain, with a whitelist-based approach for exceptions. This nearly eliminates the possibility of cross-site-scripting vulnerabilities.
All sensitive actions are authenticated using a token and/or a digital signature, to protect against cross-site request forgery attacks.
We use a deterministic build process to allow reproducing the exact client-side assets based on the published source code, and ensuring the integrity of the actual assets served by the server.
For improved security, we also utilize the X-Content-Type-Options (to prevent content type sniffing), X-Frame-Options (to prevent clickjacking attacks) and X-XSS-Protection (to help prevent cross-site-scripting attacks) headers.
Open Source
The source code for our client-side and shared libraries is available for review on our GitHub and can be audited by anyone with a technical background.
Bug Bounty Program
We welcome security audits and offer a bug bounty for responsibly disclosing security issues or breaches in our client-server model.
Our bug bounty program is managed by Crowdcurity. Please refer here for more details.
Cryptography
We use the browser's built-in CSPRNG (crypto.getRandomValues) as the sole source for entropy. Older browsers without that are simply not supported, and are not offered any PRNG fallbacks.
We generate deterministic K values for ECDSA signatures, as per RFC 6979.
Email Authenticity
To prevent email spoofing and phishing attacks, our domains are configured with a strict DKIM and SPF policies.
Please note that even with these measures in place, we will never ask for your passwords over email, and it is still important to verify you're on the correct Bitrated.com domain and under SSL (look for the green padlock in the address bar) when providing passwords to our web interface.
Private Keys & Passwords Schema
The security schema we use aims to strike a balance between usability and security. Specifically, these are our design motivations and goals:
As history shows, users cannot be trusted to provide a password strong enough to protect their funds. Therefore, we generate a strong and resistance to brute-force attacks password for them.
Users are not to be expected to remember a long machine-generated password. Therefore, we only require it once when logging-in to the account, and remember it from this point onwards.
Gaining unauthorized access to a logged-in browser session should not provide access to user funds. Therefore, we introduced an additional user-provided 2FA password that is required for controlling funds and authorizing transactions.
User-provided password might be weak and prone to brute-force attacks. Therefore, we use a strong Scrypt-based password derivation function.
User access to their keys and funds should not depend on the availability of Bitrated. Therefore, keys are derived directly from the user's passwords with no involvement from our servers.
To achieve that, our passwords and private keys schema involves two separate private keys with varying security properties:
Identity Key - derived from the generated mnemonic passphrase and used to control the user's identity. This key is used for the login process, as well as for authenticating the user's statements and actions (such as signing reviews, agreeing to a contract, updating profile fields, etc), but not for controlling funds.
Strength: the mnemonic passphrase is composed of 16 words from a 2048 words list, which provides 176 bits of entropy.
KDF parameters:
Scrypt(mnemonic, salt='Bitrated-Auth'||username, N=14, r=8, p=1)
Handling of keys: once logged in to your Bitrated account, this key is kept in your local browser storage until you logout. You are not required to remember this password (as you won't need to type it often), but must keep a secure copy of it.
Hardened Key - derived from a combination of the identity key and the user-provided 2FA password. The hardened key is used as an HD master for the keys used in multi-signature contracts and is required for controlling funds.
Strength: deriving the hardened key requires both the generated mnemonic (176 bits of entropy) and the user-provided 2FA password (whose strength is dependent on the user).
KDF parameters:
Scrypt(password_2fa, salt=sha256(identity_key), N=16, r=8, p=1)
Handling of keys: the 2FA password is only requested when authorizing transactions. The hardened key only exists in-memory for a short period of time, and is scrubbed immediately after signing the transaction. It is never stored on your browser, and you will be required to type it from time to time.
Trustless Server Model
We strive for a security model that requires as little trust as possible on our servers. While we're not there yet, our goal is to have the server-side environment operate as a simple public repository of signed user messages, where the client always considers the server to be potentially hostile and verifies everything locally.
Our current security model ensures that:
No passwords/private keys are ever processed/stored on our servers, not even in encrypted/hashed form.
Private keys are derived from the user's passwords and are fully recoverable in case Bitrated becomes unavailable.
To provide accountability for the data our APIs provide, we provide signed HTTP responses that allows proving the response originated from our servers.
All user data is digitally signed by the user, to prevent unauthorized modifications (even by Bitrated itself).
In the future, we also plan to:
Register our users public keys on a public blockchain, to prevent unauthorized modifications by the server and to eliminate our role as a trusted CA.
Announce all user actions and data to a public blockchain (as a merkle root hash), to ensure the consistency of our data, make censorship attempts detectable, and prevent forking (where the server shows different information to different users).
Announce new client-side code releases to a public blockchain (with the Git commit hash and a merkle root of the compiled client-side assets), allowing users to ensure they're running the same release published on our GitHub repository.
Provide a browser extensions that verifies the integrity of the assets returned from our web servers.
Encrypt user data end-to-end whenever possible.
Make the client-side environment resistant to active server-side attacks by verifying everything and trusting nothing.
Public key verification
To authenticate messages from the Bitrated staff, we will provide a digital signature from our
Bitcoin address 19AENxshHjdjsQrJfawCaudxaTAaNHxqbd
.
To prevent an attacker from modifying our published Bitcoin address, we have permanently embedded it into the Bitcoin blockchain in a way that is nearly impossible to modify, and becomes exponentially more difficult as time goes by.
The public key can be verified by taking the following procedure:
- Take the SHA256 of our domain name ("bitrated.com").
- Create a Bitcoin address using that hash as the private key (both compressed or uncompressed).
- Find the first transaction with that address as its input address.
- The output address of that transaction is our public key.
If its ever required to change the public key, the announcement will be signed with the old public key.