Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

A Social Account Recovery Pallet #4531

Merged

Conversation

shawntabrizi
Copy link
Member

@shawntabrizi shawntabrizi commented Jan 4, 2020

Recovery Pallet

Overview

The Recovery pallet is an M-of-N social recovery tool for users to gain
access to their accounts if the private key or other authentication mechanism
is lost. Through this pallet, a user is able to make calls on-behalf-of another
account which they have recovered. The recovery process is protected by trusted
"friends" whom the original account owner chooses. A threshold (M) out of N
friends are needed to give another account access to the recoverable account.

Recovery Configuration

The recovery process for each recoverable account can be configured by the account owner.
They are able to choose:

  • friends - The list of friends that the account owner trusts to protect the
    recovery process for their account.
  • threshold - The number of friends that need to approve a recovery process for
    the account to be successfully recovered.
  • delay_period - The minimum number of blocks after the beginning of the recovery
    process that need to pass before the account can be successfully recovered.
    There is a configurable deposit that all users need to pay to create a recovery
    configuration. This deposit is composed of a base deposit plus a multiplier for
    the number of friends chosen. This deposit is returned in full when the account
    owner removes their recovery configuration.

Recovery Lifecycle

The intended lifecycle of a successful recovery takes the following steps:

  1. The account owner calls create_recovery to set up a recovery configuration
    for their account.
  2. At some later time, the account owner loses access to their account and wants
    to recover it. Likely, they will need to create a new account and fund it with
    enough balance to support the transaction fees and the deposit for the
    recovery process.
  3. Using this new account, they call initiate_recovery.
  4. Then the account owner would contact their configured friends to vouch for
    the recovery attempt. The account owner would provide their old account id
    and the new account id, and friends would call vouch_recovery with those
    parameters.
  5. Once a threshold number of friends have vouched for the recovery attempt,
    the account owner needs to wait until the delay period has passed, starting
    when they initiated the recovery process.
  6. Now the account owner is able to call claim_recovery, which subsequently
    allows them to call as_recovered and directly make calls on-behalf-of the lost
    account.
  7. Using the now recovered account, the account owner can call close_recovery
    on the recovery process they opened, reclaiming the recovery deposit they
    placed.
  8. Then the account owner should then call remove_recovery to remove the recovery
    configuration on the recovered account and reclaim the recovery configuration
    deposit they placed.
  9. Using as_recovered, the account owner is able to call any other pallets
    to clean up their state and reclaim any reserved or locked funds. They
    can then transfer all funds from the recovered account to the new account.
  10. When the recovered account becomes reaped (i.e. its free and reserved
    balance drops to zero), the final recovery link is removed.

Malicious Recovery Attempts

Initializing a the recovery process for a recoverable account is open and
permissionless. However, the recovery deposit is an economic deterrent that
should disincentivize would-be attackers from trying to maliciously recover
accounts.

The recovery deposit can always be claimed by the account which is trying to
to be recovered. In the case of a malicious recovery attempt, the account
owner who still has access to their account can claim the deposit and
essentially punish the malicious user.
Furthermore, the malicious recovery attempt can only be successful if the
attacker is also able to get enough friends to vouch for the recovery attempt.
In the case where the account owner prevents a malicious recovery process,
this pallet makes it near-zero cost to re-configure the recovery settings and
remove/replace friends who are acting inappropriately.

Safety Considerations

It is important to note that this is a powerful pallet that can compromise the
security of an account if used incorrectly. Some recommended practices for users
of this pallet are:

  • Configure a significant delay_period for your recovery process: As long as you
    have access to your recoverable account, you need only check the blockchain once
    every delay_period blocks to ensure that no recovery attempt is successful
    against your account. Using off-chain notification systems can help with this,
    but ultimately, setting a large delay_period means that even the most skilled
    attacker will need to wait this long before they can access your account.
  • Use a high threshold of approvals: Setting a value of 1 for the threshold means
    that any of your friends would be able to recover your account. They would
    simply need to start a recovery process and approve their own process. Similarly,
    a threshold of 2 would mean that any 2 friends could work together to gain
    access to your account. The only way to prevent against these kinds of attacks
    is to choose a high threshold of approvals and select from a diverse friend
    group that would not be able to reasonably coordinate with one another.
  • Reset your configuration over time: Since the entire deposit of creating a
    recovery configuration is returned to the user, the only cost of updating
    your recovery configuration is the transaction fees for the calls. Thus,
    it is strongly encouraged to regularly update your recovery configuration
    as your life changes and your relationship with new and existing friends
    change as well.

Interface

Dispatchable Functions

For General Users

  • create_recovery - Create a recovery configuration for your account and make it recoverable.
  • initiate_recovery - Start the recovery process for a recoverable account.

For Friends of a Recoverable Account

  • vouch_recovery - As a friend of a recoverable account, vouch for a recovery attempt on the account.

For a User Who Successfully Recovered an Account

  • claim_recovery - Claim access to the account that you have successfully completed the recovery process for.
  • as_recovered - Send a transaction as an account that you have recovered. See other functions below.

For the Recoverable Account

  • close_recovery - Close an active recovery process for your account and reclaim the recovery deposit.
  • remove_recovery - Remove the recovery configuration from the account, making it un-recoverable.

For Super Users

  • set_recovered - The ROOT origin is able to skip the recovery process and directly allow
    one account to access another.

@shawntabrizi shawntabrizi added the A3-in_progress Pull request is in progress. No review needed at this stage. label Jan 4, 2020
@shawntabrizi
Copy link
Member Author

If people wanted to review the end to end life cycle tests, now would be a good time to give feedback on the design. Otherwise, will keep this mostly on the back burner since I don't want to get too heavily involved before getting some initial feedback.

@shawntabrizi shawntabrizi added A0-please_review Pull request needs code review. and removed A3-in_progress Pull request is in progress. No review needed at this stage. labels Jan 10, 2020
@shawntabrizi shawntabrizi marked this pull request as ready for review January 10, 2020 10:44
@shawntabrizi
Copy link
Member Author

This should be totally done and ready for review + merge :)

@gavofyork
Copy link
Member

Needs to have master merged and fixed.

@shawntabrizi shawntabrizi removed the A0-please_review Pull request needs code review. label Jan 13, 2020
@shawntabrizi shawntabrizi merged commit 3ed7c8b into paritytech:master Jan 13, 2020
@shawntabrizi shawntabrizi deleted the shawntabrizi-recover-pallet branch January 13, 2020 16:52
@marceljay
Copy link

Hey Shawn, thanks for the intro at tonights's meetup, I couldn't make, it but watched it on the train.
Is there some explanation how calling on behalf of another account works? I remember that consensus on substrate is decoupled from payments (which are just an "app") and thought this might be the reason, or am I wrong? Also I did not really understand what pallets are (a concept in rust?), I could not find a good intro in the devhub.

@burdges
Copy link

burdges commented Feb 6, 2020

Just fyi..

It appears custody solutions denominated in euros are required to provide account recovery using the users identity. There was one grant application to solve this without completely centralizing.

I'd kinda like us to fund it so we can make them use Rogaway's Adept Secret Sharing whenever he releases it, instead of their home brewed thing. We do not however have enough interest from custody solutions to justify funding it though, but maybe useful here too.

RustySecrets should eventually implement Rogaway's Adept Secret Sharing, btw.

This would not impact this pull request, merely pointing this out.

@shawntabrizi
Copy link
Member Author

@marceljay All the magic around calling on behalf of another account comes from the as_recovered function:

#[weight = <Passthrough<T::AccountId, <T as Trait>::Call>>::new()]
fn as_recovered(origin,
	account: T::AccountId,
	call: Box<<T as Trait>::Call>
) -> DispatchResult {
	let who = ensure_signed(origin)?;
	// Check `who` is allowed to make a call on behalf of `account`
	ensure!(Self::recovered_account(&account) == Some(who), Error::<T>::NotAllowed);
	call.dispatch(frame_system::RawOrigin::Signed(account).into())
}

Specifically the fact that we are able to create a new origin from within the runtime logic:

frame_system::RawOrigin::Signed(account)

The ability to do this is an extremely privileged action, but since we are runtime developers, we are allowed to do it. The only sense of identity that our runtime logic cares about is this origin, so we are essentially able to make any other pallet believe the call is coming from our lost account rather than the one we have access to.

The pallet term is relatively new, but means the same thing that "runtime module" did before. Check out this #4182

FRAME is our framework for developing new Substrate pallets. Pallets are a special kind of Rust module from which Substrate runtimes can be composed. Each pallet has its own discrete logic which can modify the features and functionality of your blockchain's state transition function.

@marceljay
Copy link

Okay there was definitely some confusion on my side due to the changed wording.
FRAME = SRML
Pallet = Module
(tbh, i liked the original names much better)

Regarding the code: my rust knowledge is too basic to understand the code. But I think my questions was rather how consensus is made based on certain function calls. Would definitely like to understand this in the future.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants