dfinity / wg-identity-authentication

Repository of the Identity and Wallet Standards Working Group
https://wiki.internetcomputer.org/wiki/Identity_%26_Authentication
Apache License 2.0
26 stars 8 forks source link

ICRC-49: Call Canister #114

Open plitzenberger opened 6 months ago

plitzenberger commented 6 months ago

This Standard describes how the relying party can request calls to 3rd party canister executed by the signer using the requested identity. All requests are subject to user approval to prevent misuse of this interaction.

Draft Document: icrc_49_call_canister.md

kristoferlund commented 5 months ago

@frederikrothenberger I am moving a follow up question here regarding your example:

Do you wish to connect to https://awesomedapp.com/ and share the following identities:

- Social Media (njsxs-anfxg-se6ti-anmmo-qdc7u-wtcd5-aqn6g-i6hna-uelej-nypov-6qe)
 - Allow the dapp to initiate transactions with this identity
- Read Only Identity (hcg7g-lsf6s-ghhip-rjn6u-jkbdw-wsdzw-rfdwn-kd2ii-nicnq-dzsdp-aae)
 - Allow the dapp to initiate transactions with this identity
- Top Secret (444v7-kuyfk-v4b5q-sbxol-2tjqu-jpohg-bpdog-pr53h-6jppm-uk2lw-jae)

We can assume a multi canister app might make more than one call to icrc25_request_permissions during the span of a session. Have you discussed how the signer can find relevant context to show the user when the icrc_49_call_canister_call scope is requested. https://awesomedapp.com represents the domain the dapp is running on. But that is most likely not enough context to convey any meaningful information to the user. It might be at "first connect", when dapp is started. But if additional permissions are requested further on, https://awesomedapp.com does no longer provide the details the user needs to see to approve/reject. Of course, there is the target, but showing the user Do you wish to connect to "ryjl3-tyaaa-aaaaa-aaaba-cai", does not convey any meaningful information either.

Have you discussed any mechanism that would allow the signer to translate canister ids to something more legible? The relying party cannot be trusted to give a name since it can be malicious.

An example scenario could be:

App is a Dex.

  1. App starts, requests icrc_49_call_canister_call permissions to interact with the dex canisters
  2. Later, user wants to make a trade, app requests icrc_49_call_canister_call permissions to interact with a specific token ledger canister
sea-snake commented 5 months ago

Have you discussed any mechanism that would allow the signer to translate canister ids to something more legible? The relying party cannot be trusted to give a name since it can be malicious.

Isn't this ICRC-21?

Also for token standards supported by the signer, the signer could identify that the canister is a ledger and the method called upon this ledger is e.g. transfer. Then it could decode and show the arguments to the user e.g. Transfer 10 ICP to account X.

I've implemented this second approach in Slide wallet. Most of this call identification has been abstracted in a separate tokens-js libary that's still WIP.

Showing consent messages with ICRC-21 is still on my todo list, this primarily helps with explaining calls to canisters that aren't ledgers.

image

sea-snake commented 5 months ago
  1. App starts, requests icrc_49_call_canister_call permissions to interact with the dex canisters

For a dapp to interact with it's own canisters I would opt for ICRC-34 which avoids user interaction all together by getting a delegation for the dapp canister ids as targets.

kristoferlund commented 5 months ago

Isn't this ICRC-21?

Yeah, for the actual call there is the consent message, that is great. There, the canister can provide all context needed to let the user make an informed decision.

I am talking about the icrc25_request_permissions call. The app is requesting permissions to a canister where the only available context is the canister id, which to a user means nothing.

Relying on the signer to "identify that the canister is a ledger", that places lots of weight on the signer (wallet) developer. First there are token ledgers, then there are NFT canisters, then .. staking protocols.. and so on. With a similar setup like the consent message interface, perhaps canisters can self identify?

For future consideration, I understand this is out of scope for now:

Canister self identification

type icrcX_canister_info_preferences = record {
    // Same semantics as HTTP Accept-Language header
    language: text;
};

type icrcX_canister_info_request = record {
    // User preferences with regards to the info message presented to the end-user.
    consent_preferences: icrcX_canister_info_preferences;
};

type icrcX_canister_info_ok = record {
    // Human readable name of the canister.
    name: text;
    // Human readable description of the canister.
    description: text;
    // Same semantics as HTTP lang attribute
    language: text;
};

type icrcX_canister_info_response = variant {
    // The call is ok, consent message is provided.
    Ok: icrcX_canister_info_ok;
    // The call is not ok, error is provided.
    Err: icrcX_canister_info_error;
};

service : {
    // Returns a human-readable canister info message.
    icrcX_canister_info: (icrcX_canister_info_request) -> (icrcX_canister_info_response);

      // Returns a list of supported standards this canister implements.
    // The result should always have at least one entry: record { name = "ICRC-1"; url = "https://github.com/dfinity/ICRC-1/tree/main/standards/ICRC-1" }
    // This query call must not require authentication.
    icrcX_supported_standards : () -> (vec record { name : text; url : text }) query;
}
sea-snake commented 5 months ago

Relying on the signer to "identify that the canister is a ledger", that places lots of weight on the signer (wallet) developer. First there are token ledgers, then there are NFT canisters, then .. staking protocols.. and so on. With a similar setup like the consent message interface, perhaps canisters can self identify?

That would be rather nice, right now I try calling all the "icrc specific supported standards" methods on a canister to see what doesn't error and what does. Would be really helpful to have a standardized "info and supported base standards method" as you described above.

frederikrothenberger commented 5 months ago

@kristoferlund: This is definitely an important issue but I agree that it is out of scope. We had some previous discussions in the working group about that (which is why @plitzenberger has already reserved an ICRC number for a standard on that). Sadly the issue is missing context (@plitzenberger, do you remember where we had this discussion / would you mind fleshing out the issue a bit?).

The general conclusion was, that we need some sort of shared registry (e.g. NNS controlled), as self-declaration is broken due to impersonation (i.e. all applications must have distinct metadata in order to not cause confusion on the users side). So far, the most promising approach is to use proposals to add and update entries in the DAO controlled registry placing the burden to review and flag impersonations on the entities that have voting power. SNSes are essentially already behaving like this (and IIRC there is an SNS index canister to find all the SNSes).

I think the above suggestion here is not enough, as a different front-end interacting with the same backend is still a different application. So we need to accommodate both front-end application metadata and pure back-end infrastructure metadata (e.g. for ledgers).

For now (until we have a better model), I would suggest the following:

I would more than welcome for this to be picked up by the community. For now, regarding ICRC-25, I think we can get away with simply declaring it out of scope. This will aggravate the issue once signers are commonplace, providing more motivation and pressure to build a solution.

sea-snake commented 4 months ago

The general conclusion was, that we need some sort of shared registry (e.g. NNS controlled), as self-declaration is broken due to impersonation (i.e. all applications must have distinct metadata in order to not cause confusion on the users side)

Maybe identifying could be done by origin?

  1. Canister A has a method that returns origin B
  2. Origin B has a file at .well-known/trusted_canisters
  3. Signer calls method from step 1 and then checks if canister is in list of step 2
  4. If this is true, canister clearly shows origin B

This would clearly connect a canister to a specific origin making it at least clear to the end user with which service it's communicating.

Additional metadata like a name and description could also be fetched and shown in step 5. This data is clearly something that could be impersonated but so can anyone create an ICRC-1 canister that calls itself ICP, now you could at least see that the domain invalid.

This also would make it easier to add tokens to a wallet as a user, you just enter the domain instead of principal.

frederikrothenberger commented 4 months ago

Additional metadata like a name and description could also be fetched and shown in step 5. This data is clearly something that could be impersonated but so can anyone create an ICRC-1 canister that calls itself ICP, now you could at least see that the domain invalid.

How would the domain be invalid?

Let's say we do validate according to the procedure you describe, we still face the issue that there can be the original setup:

Both sets of metadata would validate according to the outlined procedure (so no invalid domain warning).

The problem is not associating metadata with a canister / domain. The problem is making sure, that that data is not impersonating some other application.

sea-snake commented 4 months ago

canister B, domain avvesome.com, which copies all the metadata from awesome.com / canister A verbatim including stealing the logo, etc.

Yeah similar domains would indeed still be a limitation :/

kristoferlund commented 4 months ago

I agree with @frederikrothenberger that the way forward is a decentralised centralised registry. In the "regular world" there is always such a list, maintained by a "trusted party". When I am asked to sign a banking transaction in my Swedish banking app, I am asked to sign a message using another app - the "BankId" app. The organisation building the BankId app maintains the list and guarantees that no one is impersonating my bank. Trusted origin and trusted consent message allows me to sign the message without being too nervous that someone is stealing my funds.

Indeed, this would be a good project to be picked up by the community.