You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In v0.0.1 of ONE Wallet, the client may act on its own without any input from the authenticator. This complies with the design in Protocol v0.0.3, but is certainly undesirable. This issue makes the wallet as vulnerable as MetaMask, which is known to be prone to large scale client-side hacks. This must be improved before the wallet can be released to beta users, so we can avoid major security incidents later.
The core weakness resides in the small search space in how EOTP is generated from an OTP and several other client-side parameters (hseed, nonce). See code at
// 4 bytes for OTP, 2 bytes for nonce, 26 bytes for seed hash
Since the OTP is confined to a 6-digit numerical number, and the generation process relies on SHA256, the right OTP (and by extension, its EOTP) at any given time can be easily enumerated by brute-force, for any given leaf hash value. See for the code of doing so at
Over the weekend of 6/18/2021 I designed several methods to address this issue, with the goal so that the client cannot act on its own without the correct OTP code from the authenticator. Different candidate methods have different security strengths, and some of them are composable (introducing multiplicative complexity) with each other. For extreme security, I also considered the use of a generic private-key signing device, Yubikey. My plan is to document these methods in detail this week and submit them for review as soon as possible. While they are being reviewed, I will implement them by the 6/30/2021, and make another iteration in the following week based on the review feedback.
Another miscellaneous issue is that the client should ensure a commit is confirmed on the blockchain, before sending out a reveal. This is necessary to prevent man-in-the-middle attacks, which the attacker may stall both the client's commit and reveal and insert the attacker's own altered commit and reveal using the revealed proofs provided by the client.
Overall, here is the TODO list (best viewed on desktop to show indentions correctly):
1. Make the client resilient to brute-force attacks
a. Implement a new method that imposes a difficulty parameter on operation execution
i. Make the difficulty parameter control the extra degree of randomness in EOTP generation process
ii. Control the difficulty parameter such that given an OTP, it shall not take more than 5 seconds to execute.
iii. Ensure the difficulty parameter does not slow down the Merkle Tree generation process during wallet creation
iv. Restrict the randomness introduced by the difficulty parameter to a deterministic process controlled by the authenticator seed (OTP Seed), so the wallet may still be fully recovered from the authenticator.
b. Replace EOTP hash function with a stronger candidate, Argon2
i. Explain the weaknesses of alternative candidates: scrypt, bcrypt, sha256, keccak256
ii. Brute-force resilliance estimation utility for the candidates
c. Document and analyze this method and the choice of the hash function
In v0.0.1 of ONE Wallet, the user is asked to provide a 0x... style recovery address during the wallet creation process. The user is also asked to specify a daily spending limit for the wallet (defaults to 1000 ONE). Both parameters are optional. In addition, the user is provided the option to adjust the wallet lifespan between 6 months and 2 years (defaults to 1 year).
This process creates too much friction on the user. It was suggested in a feedback session on 6/18/2021 to remove or hide the spending limit and recovery address input boxes, such that the user would ordinarily complete the creation process by a series of clicks (and one OTP input) without having to make a decision on an appropriate daily spending limit or choosing a recovery address. Thus, most (if not all) users would create a wallet with default settings (daily spending limit at 1000 ONE, and no recovery address). Afterwards, the user may adjust the daily spending limit and the recovery address on the user interfacing showing this particular wallet. This simplified creation process removes any perceived complexity or friction on the user, and reduces the burden of customer support and operations.
I concur with this suggestion. Specifically, I am more inclined towards hiding these settings such that it may only be set after the user conciously makes a decision of setting them upfront, e.g. by clicking "advanced settings", similar to the current UI for adjusting wallet lifespan.
In addition to this change, the page that allows the user to restore a wallet locally from the authenticator is yet to be implemented. The current client bundle size (~10MB before gzip, or ~2MB after gzip) needs to be reduced to ideally less than 2MB before gzip, so that an user with an average Internet connection can load the wallet within less than 2 seconds. Each second after 2 second may increase bounce rate by ~5%. See also previous issue #2
4. Add buttons and a screen on wallet display page, that allow the user to increase or decrease the wallet's spending limit
a. If the user does not use any composable authentication method (i.e. has not set double OTP)
i. Bound the limit to be no less than 0, and no more than 2x of the current limit + 100 ONE.
ii. The new limit only takes effect on the next day.
iii. Provide hints that advises the user: if they want a much higher limit but do not want to wait, they should create a new wallet and set a higher limit upfront.
b. If the user has already set a composable authentication method, require the user to use the composable authentication method (double OTP) to adjust the limit
i. The new limit is no longer bounded, but only takes effects on the next day.
In the current release, the Test Relayer is exposed to the public. Although the Test Relayer implements basic authentication by requiring a shared secret value in every request's header, the shared secret value is provided at the client as plaintext. This means an attacker can easily spam the Relayer with frivilous wallet creation or commit requests, and deplete the small gas reserve the Relayer keeps for paying transaction gas fees on behalf of legitimate users. During beta testing, it is highly likely that at least one person out of 1000 people would attempt to do so.
While improvements on the blockchain are still pending review (e.g. harmony-one/bounties#35) to gradually and fundamentally remove the necessity of Relayer, it is imperative for us to implement protection mechanisms to provide basic resilience against typical DDOS attack such as the one described above. To do so, I plan to implement a combination of traditional techniques in web services: fingerprinting, rate-limiting, delayed response, and response prioritization. These protections are optional if any user wants to run their own Relayer, but they will be activated on the Test Relayer we provide to beta users. A helpful paper on this subject is Host Fingerprinting and Tracking on the Web: Privacy and Security Implications
Here is the TODO list:
1. Compute stateless incoming request fingerprints using the hash of concatenations of geo-IP, user-agent, HTTP ACCEPT header, and wallet root hash.
2. Impose rate-limits for requests based on fingerprints. Requests exceeding rate limits per fingerprint will be responded with error-429 (Too Many Requests), subject to a delay that is doubled per consecutive error-429 resposnes, starting from 1 second.
a. Wallet creation: 1 per minute per fingerprint, and 30 per minute globally
i. Implement response prioritization: if a request is capped by global rate limit, it will be placed in a priority queue instead of responded with error-429 error. A counter will be kept for the number of requests in the queue per geo-IP, user-agent, and fingerprint. When an item is placed in queue, its priority will be set to -1 multiply by the sum of the counter values for its corresponding geo-IP, user-agent, and fingerprint. The server periodically (at a small interval) picks the request with the highest priority to serve. Any request staying for more than 10 seconds is automatically removed.
b. Commit: 30 per minute per fingerprint
c. Reveal (of any kind): 30 per minute per fingerprint
d. Others: 6 per minute per fingerprint
3. Implement response prioritization: when an incoming requests exceeds the rate limit, it will be placed in a priority queue for the type of the request. The request with the smallest The priority is determined as the following: the sum of number of requests from each of the following
IV. Smart Contract
The smart contract needs to be adjsuted to reflect the new, one-time recovery mechanism specified in Part I §3. It should also allow one-time setup of the recovery address as specified in Part II §3, as well as the daily spending limit adjustment specified in Part II §4. The double-OTP activation specified in Part I §2(a)(ii) would require the smart contract to add another root hash value1, since the Merkle Tree generated by double-OTPs would be different than the original. After activating double-OTP, all operations2 that require root hash value verification should be verified against the new root hash value instead.
[1] We keep the original root-hash value so we can still use it to identify the wallet and use it as a flag to indicate the wallet has double OTP activated.
Additionally, during the week of 6/21/2021, a potential man-in-the-middle attack is identified (during a conversation with @ivan-homoliak-sutd), where the attacker may stall the user's commit using an overwhelming amount of spam trasactions, and insert the attacker's own commit and reveal in the same block ahead of the user's reveal using an overwhelmingly high amount of gas. A solution to completely prevent this is already found and will be implemented very soon.
There are substantial developments of the fundamental protocols and design since Protocol v0.0.3 and Wiki v0.1.4. The TODO list consists of the major components:
1. The introduction of the new methods for client security in Part I
c. Discussions with others who are working on this project
VI. Connect Wallet with dApps
Traditionally, web dApps connects to a browser-extension wallet (e.g. MetaMask) by using an "provider" instance exposed by the wallet in the browser session. As wallets and dApps are moving towards mobile platforms, this communication architecture is replaced by a standard interface and bridged architecture, such as WalletConnect. In WalletConnect, implementation variations between different wallets are also conveniently abstracted away. This enables smart contract wallet to implement support for this universal connection method, and allow the user to connect the smart contract wallet from a dApp. After a dApp is connected, the dApp may initiate operations from its own user interface (such as buying and selling NFT, sending funds to a swap exchange), and ask the user to approve the operations in the wallet user interface, whenever approval is needed (such as sending a transaction, signing a transaction to be sent later).
Implementing WalletConnect opens doors to a wide array of applications for ONE Wallet, as long as the dApp also implements WalletConnect. However, there is no reference implementation of WalletConnect for smart wallet available aside from Argent (https://github.com/argentlabs/argent-contracts/tree/develop/contracts), which has no documentation on the workflow or the extent of support and integration. WalletConnect only provides mobile platform libraries (React Native, Swift, Kotlin) for development. To support WalletConnect, we need to make our implementation for the complete technical specification of WalletConnect.
The amount of work required for a reliable implementation is very significant. Thus, this section should be considered as optional prior to launching to beta users, and it should have lower priority than the TODO lists in Part I through V.
To reduce the implementation complexity and workload, we should also prioritize on supporting only the most common JSON-RPC method: eth_sendTransaction, which the dApp to request the wallet to send a transaction. We should also limit the initial use case for calling this method to sending funds only, as opposed to submitting arbitrary data to the blockchain.
The other JSON-RPC methods personal_sign, eth_sign, eth_signTypedData, eth_signTransaction, eth_sendRawTransaction mostly deal with non-realtime use cases which a transaction is signed at first but sent much later. They are uncommon use cases, yet they introduce a very high amount of implementation complexity - since smart contract wallets do not have the concept of "sending raw transaction", and ONE Wallet does not have the ability to send trasactions and attach arbitrary data at this time. To validate signatures, we will also need to implement the smart contract signature validation interface per EIP-1271. This will require us to create new commit-reveal methods and state-variables specifically for storing signatures and hashes of signed messages on the smart contract.
The tentative TODO list:
1. Implement encrypted connection and session management, per WalletConnect spec
2. Implement user interface for parsing a WalletConnect QR code (via copy-paste) and parsing the underlying wc:... connection string.
polymorpher
changed the title
TODO before launching to beta users (~1000 people)
TODO before launching to a larger set of users (10k-100k people)
Jun 29, 2021
This document is based on v0.0.1 of ONE Wallet, released on 6/18/2021: https://github.com/polymorpher/one-wallet/tree/7e6aed60fc19b317fe733112bf18739775f05c5c/code .
I. Client Security
In v0.0.1 of ONE Wallet, the client may act on its own without any input from the authenticator. This complies with the design in Protocol v0.0.3, but is certainly undesirable. This issue makes the wallet as vulnerable as MetaMask, which is known to be prone to large scale client-side hacks. This must be improved before the wallet can be released to beta users, so we can avoid major security incidents later.
The core weakness resides in the small search space in how EOTP is generated from an OTP and several other client-side parameters (hseed, nonce). See code at
one-wallet/code/lib/onewallet.js
Line 25 in ae1b113
Since the OTP is confined to a 6-digit numerical number, and the generation process relies on SHA256, the right OTP (and by extension, its EOTP) at any given time can be easily enumerated by brute-force, for any given leaf hash value. See for the code of doing so at
one-wallet/code/lib/onewallet.js
Line 141 in afe39e6
Over the weekend of 6/18/2021 I designed several methods to address this issue, with the goal so that the client cannot act on its own without the correct OTP code from the authenticator. Different candidate methods have different security strengths, and some of them are composable (introducing multiplicative complexity) with each other. For extreme security, I also considered the use of a generic private-key signing device, Yubikey. My plan is to document these methods in detail this week and submit them for review as soon as possible. While they are being reviewed, I will implement them by the 6/30/2021, and make another iteration in the following week based on the review feedback.
Another miscellaneous issue is that the client should ensure a commit is confirmed on the blockchain, before sending out a reveal. This is necessary to prevent man-in-the-middle attacks, which the attacker may stall both the client's commit and reveal and insert the attacker's own altered commit and reveal using the revealed proofs provided by the client.
Overall, here is the TODO list (best viewed on desktop to show indentions correctly):
II. Basic User Interface
In v0.0.1 of ONE Wallet, the user is asked to provide a
0x...
style recovery address during the wallet creation process. The user is also asked to specify a daily spending limit for the wallet (defaults to 1000 ONE). Both parameters are optional. In addition, the user is provided the option to adjust the wallet lifespan between 6 months and 2 years (defaults to 1 year).This process creates too much friction on the user. It was suggested in a feedback session on 6/18/2021 to remove or hide the spending limit and recovery address input boxes, such that the user would ordinarily complete the creation process by a series of clicks (and one OTP input) without having to make a decision on an appropriate daily spending limit or choosing a recovery address. Thus, most (if not all) users would create a wallet with default settings (daily spending limit at 1000 ONE, and no recovery address). Afterwards, the user may adjust the daily spending limit and the recovery address on the user interfacing showing this particular wallet. This simplified creation process removes any perceived complexity or friction on the user, and reduces the burden of customer support and operations.
I concur with this suggestion. Specifically, I am more inclined towards hiding these settings such that it may only be set after the user conciously makes a decision of setting them upfront, e.g. by clicking "advanced settings", similar to the current UI for adjusting wallet lifespan.
In addition to this change, the page that allows the user to restore a wallet locally from the authenticator is yet to be implemented. The current client bundle size (~10MB before gzip, or ~2MB after gzip) needs to be reduced to ideally less than 2MB before gzip, so that an user with an average Internet connection can load the wallet within less than 2 seconds. Each second after 2 second may increase bounce rate by ~5%. See also previous issue #2
In summary, here is the TODO list:
one1....
style address as recovery address #8III. Basic Relayer Protection
In the current release, the Test Relayer is exposed to the public. Although the Test Relayer implements basic authentication by requiring a shared secret value in every request's header, the shared secret value is provided at the client as plaintext. This means an attacker can easily spam the Relayer with frivilous wallet creation or commit requests, and deplete the small gas reserve the Relayer keeps for paying transaction gas fees on behalf of legitimate users. During beta testing, it is highly likely that at least one person out of 1000 people would attempt to do so.
While improvements on the blockchain are still pending review (e.g. harmony-one/bounties#35) to gradually and fundamentally remove the necessity of Relayer, it is imperative for us to implement protection mechanisms to provide basic resilience against typical DDOS attack such as the one described above. To do so, I plan to implement a combination of traditional techniques in web services: fingerprinting, rate-limiting, delayed response, and response prioritization. These protections are optional if any user wants to run their own Relayer, but they will be activated on the Test Relayer we provide to beta users. A helpful paper on this subject is Host Fingerprinting and Tracking on the Web: Privacy and Security Implications
Here is the TODO list:
IV. Smart Contract
The smart contract needs to be adjsuted to reflect the new, one-time recovery mechanism specified in Part I §3. It should also allow one-time setup of the recovery address as specified in Part II §3, as well as the daily spending limit adjustment specified in Part II §4. The double-OTP activation specified in Part I §2(a)(ii) would require the smart contract to add another root hash value1, since the Merkle Tree generated by double-OTPs would be different than the original. After activating double-OTP, all operations2 that require root hash value verification should be verified against the new root hash value instead.
[1] We keep the original root-hash value so we can still use it to identify the wallet and use it as a flag to indicate the wallet has double OTP activated.
[2] This does not include recovery.
Additionally, during the week of 6/21/2021, a potential man-in-the-middle attack is identified (during a conversation with @ivan-homoliak-sutd), where the attacker may stall the user's commit using an overwhelming amount of spam trasactions, and insert the attacker's own commit and reveal in the same block ahead of the user's reveal using an overwhelmingly high amount of gas. A solution to completely prevent this is already found and will be implemented very soon.
In summary, the TODO list is below:
V. Wiki and Protocol Specification
There are substantial developments of the fundamental protocols and design since Protocol v0.0.3 and Wiki v0.1.4. The TODO list consists of the major components:
VI. Connect Wallet with dApps
Traditionally, web dApps connects to a browser-extension wallet (e.g. MetaMask) by using an "provider" instance exposed by the wallet in the browser session. As wallets and dApps are moving towards mobile platforms, this communication architecture is replaced by a standard interface and bridged architecture, such as WalletConnect. In WalletConnect, implementation variations between different wallets are also conveniently abstracted away. This enables smart contract wallet to implement support for this universal connection method, and allow the user to connect the smart contract wallet from a dApp. After a dApp is connected, the dApp may initiate operations from its own user interface (such as buying and selling NFT, sending funds to a swap exchange), and ask the user to approve the operations in the wallet user interface, whenever approval is needed (such as sending a transaction, signing a transaction to be sent later).
Implementing WalletConnect opens doors to a wide array of applications for ONE Wallet, as long as the dApp also implements WalletConnect. However, there is no reference implementation of WalletConnect for smart wallet available aside from Argent (https://github.com/argentlabs/argent-contracts/tree/develop/contracts), which has no documentation on the workflow or the extent of support and integration. WalletConnect only provides mobile platform libraries (React Native, Swift, Kotlin) for development. To support WalletConnect, we need to make our implementation for the complete technical specification of WalletConnect.
The amount of work required for a reliable implementation is very significant. Thus, this section should be considered as optional prior to launching to beta users, and it should have lower priority than the TODO lists in Part I through V.
To reduce the implementation complexity and workload, we should also prioritize on supporting only the most common JSON-RPC method:
eth_sendTransaction
, which the dApp to request the wallet to send a transaction. We should also limit the initial use case for calling this method to sending funds only, as opposed to submitting arbitrary data to the blockchain.The other JSON-RPC methods
personal_sign
,eth_sign
,eth_signTypedData
,eth_signTransaction
,eth_sendRawTransaction
mostly deal with non-realtime use cases which a transaction is signed at first but sent much later. They are uncommon use cases, yet they introduce a very high amount of implementation complexity - since smart contract wallets do not have the concept of "sending raw transaction", and ONE Wallet does not have the ability to send trasactions and attach arbitrary data at this time. To validate signatures, we will also need to implement the smart contract signature validation interface per EIP-1271. This will require us to create new commit-reveal methods and state-variables specifically for storing signatures and hashes of signed messages on the smart contract.The tentative TODO list:
wc:...
connection string.VII. Staking
The text was updated successfully, but these errors were encountered: