Proposal to add security for IC wallet users

GH proposal: Proposal to add security for IC wallet users · Issue #33 · dfinity/wg-identity-authentication · GitHub

TLDR;

Problem

Users could be drained in cases where 3rd party applications don’t specify canisters as targets in a delegation identity request. We have verified this is not a problem for II or NFID users, but NFID needs a solution given it’s soon rolling out global principal support.

Proposed solution

3rd party applications requesting a global principal MUST implement a mechanism wherein wallet providers MUST verify the frontend origin can request a set of canisters as targets.

Proposed target canister implementation

We assume each wallet provider will have its own mechanism for verifying the frontend origin making the call. We propose a standard method on each target canister that wallet providers will query (as an update call for secure consensus):

// Rust implementation

#[update]
async fn get_trusted_origins() -> Vec<String> {
    vec![
        String::from("dscvr.one") // to be replaced with application's frontend origin(s)
    ]
}

Sample NFID implementation

Users authenticating to 3rd party applications that do not specify target canisters or whose targets can’t be verified WILL NOT be able to authenticate with their global profile

7 Likes

Do you mean NNS and all fungible & non fungible ledgers and everything else DSCVR uses have to add the ‘get_trusted_origins’ functions and whitelist origins like dscvr.one inside ?
If so:

  • it will be pretty slow and hard to make everyone add this
  • impossible for immutable canisters
  • only 3-4 sites on the IC will be able to use it right now
  • when the number grows to 30, if each one of these sites makes a mistake or gets taken over, it will result in a lot of users losing all of their global identity assets.
2 Likes

I need something similar for my own wallet, so it’s nice to see it standardized.

Though in the case of my own wallet:

  • User connects wallet to origin A
  • Origin A tells during connection to what canisters it wants full access
  • Wallet calls method for each of these canisters to verify origin A is in the list
  • Now the dapp on origin A can call these canisters without user interaction
  • If the dapp on origin A wants to call other canisters, it’ll go through a confirmation dialog flow where user needs to approve

The whitelisted canister flow would be likely for backend canisters of the dapp on origin A, so that the user isn’t bothered to confirm every call to the backend of the dapp.

I assume this proposal is not meant for things like ledger canisters, those canisters will likely never implement this whitelist, users are expected to confirm each call.

Personally I think a certified query call with an http method like the alternate origins for internet identity seems more useful than an update call. Also it would be way faster, cached by boundary nodes etc.

The main benefit of this proposal seems to me the added security, previously I was considering adding a whitelist to the wallet connect. But that means the user is expected to know that this list is correct and not malicious, which is something I’d like to avoid, it’s too risky. This proposal would add the security control back to the dapp canister developers, they can allow specific frontends only.

Let me know if I misunderstood anything.

Edit:
If I read the proposal again, does it actually mean that only frontends whitelisted by the ledger canister can interact with the ledger canister?

That seems indeed like @infu mentioned problematic, you can’t expect ledger canisters to update this list. As a result no frontends or only specific frontends can interact with the ledger.

Also a frontend can suddenly become malicious, I think user should always be asked to confirm calls so they know what’s happening with their assets.

3 Likes

@sea-snake you have the flow exactly correct:

Developers can openly query ledger canisters with the user’s principal/account for balances

This mechanism is specifically proposed so that developers can’t make update calls to those ledger canisters (and generally canisters they’re not in control of) on behalf of users without user approval in their wallet. As it stands today, some IC wallets do not restrict this case.

@frederikrothenberger also mentioned certified query calls might be a better option, thank you for this feedback.

2 Likes

So to be clear:

This proposal allows a frontend dapp to directly call it’s backend canister through the wallet where the wallet checks if the backend dapp indeed allows that frontend.

It’s not intended for e.g. public ledger canisters, those shouldn’t allow any frontend to make wallet calls without manual user approval.

Right?
Edit: re-read your response and it seems the case.

Regarding the origin, we probably want to be precise, just like web postmessage standard, always include protocol and include port if it’s different e.g. https://example.org or http://example.org:8080.

Detail for implementers in wallets: checking the origin of a call in a browser should be done with postMessage to another tab/window/iframe since you can’t trust a referrer header or data sent by frontend.

2 Likes

Exactly correct here, and great suggestion on protocol/port.

I’ll ask our team to make these two tweaks:

  • Certified query call
  • Protocol/port for origins

Otherwise, may I propose this as an ICRC in Github to kick off the official discussion?

3 Likes