Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: use BNS to authenticate the application #615

Open
jcnelson opened this issue Mar 4, 2019 · 13 comments

Comments

@jcnelson
Copy link
Member

commented Mar 4, 2019

Currently, the authentication flow (1) uses the application origin to derive the application private key, and (2) requires that the manifest URI matches the application's origin. The rationale of point (2) is that the application proves to the authenticator that it owns the origin, so the right application key will be derived -- a rogue client cannot derive the private key for another application. However, this treatment of the origin and manifest.json creates a few issues:

  • This makes it hard to switch the application's URL, since the origin is used to derive the key.

  • It leaves applications and users vulnerable to DNS hijacking.

  • This makes it hard to build locally-hosted apps and apps that run inside Web extensions in conjunction with the hosted browser, since the application may not even have an HTTP endpoint (let alone one that is available via HTTPS).

Instead, I propose the following "version 2" of authentication flow that will allow us to use BNS to authenticate applications. The high-level idea is that the manifest.json would be the BNS name's profile, and that the BNS name (not the origin) would be the way by which we identify applications -- including for the purposes of generating application private keys. The developer could change the application's origin by updating the BNS profile, but users would receive a warning from the authenticator when this happens.

The protocol overview is as follows:

  • Have the developer register a BNS name for the publishing the application. The BNS name is used to cryptographically identify the application. There would be one BNS name per application, and would be used to derive the application private key.

  • Have the developer structure the manifest.json as a JWT, signed by the BNS private key. Add the following data to the manifest.json:

    • The usual JWT fields (issuer, expiration date, creation date, signature)
    • The application origin
  • Have the developer include the following fields in the authentication request:

    • The BNS name of the application
    • The minimum age of the manifest.json
  • Have the authenticator take the following extra steps on sign-in if this scheme is used:

    • Resolve the application's BNS name to the manifest.json. Reject the auth request if the manifest.json is malformed or cannot be resolved.
    • Use the BNS public key to authenticate the signature of the manifest.json. Reject the auth request if the signature is invalid.
    • Check the manifest timestamp against the auth request to see that it is fresh. Reject the auth request if the manifest.json's timestamp is too old.
    • Check the manifest's application origin. Reject the auth request if it does not match the redirect URI.
  • Have the authenticator take the following steps to generate the app private key:

    • If the user has signed into the app already using the app origin to generate the private key:
      • Update the application entry in the user's profile to include the application BNS name, if we haven't done so already.
      • On future sign-ins, verify that the BNS name's manifest.json's app origin matches the app entry. If the origin changes, then alert the user that the app origin changed. If the user is okay with this, then add the new origin as the "current" origin, BUT preserve the original origin so we can continue to derive the right private key.
    • If the user has NOT signed into the app already:
      • Use the BNS name to derive the application private key. Insert a bns://-prefixed origin into the user's profile for this app, so the authenticator knows in the future to use the BNS name to generate the app private key. Include the app's (DNS) origin in the entry, and in future sign-ins, alert the user if the app origin fetched via BNS does not match the auth request (indicates the app origin changed).
    • NOTE: in both cases above, we are inserting both the app's BNS name and DNS origin into the user's profile -- we're just structuring the record to indicate to the authenticator which name to use to generate the app private key.

The "wins" this scheme gets us are:

  • We get to use immutable BNS names to derive future application private keys
  • Developers can host the manifest.json anywhere
  • The authenticator detects when the application origin changes, and prompts the user to verify that the new origin is legit.
  • The user continues to generate the same private key even if the app origin changes.

What do you think? @larrysalibra @zone117x @yknl @hstove

@moxiegirl

This comment has been minimized.

Copy link
Contributor

commented Mar 5, 2019

@jcnelson Maybe post this in the forum when you want feedback from App developers.

@kantai

This comment has been minimized.

Copy link
Member

commented Mar 5, 2019

This proposal makes sense to me. In order to be backwards compatible with the current version of blockstack.js, the apps key would have to be unchanged, since its currently an array of strings.

I would add that in implementing this, we should extend the key derivation path to use the full hash160 of the app name.

Also, note that we won't be able to detect and apply backwards-compatibility fixes for single-player applications without some additional measures.

@jcnelson

This comment has been minimized.

Copy link
Member Author

commented Mar 5, 2019

This proposal makes sense to me. In order to be backwards compatible with the current version of blockstack.js, the apps key would have to be unchanged, since its currently an array of strings.

Sounds reasonable. In implementing this, I'd take the opportunity to define an appsData map that links versioned information to application names, where the "version" refers to the version of the authentication protocol. I think adopting a schema like this would help us get into the habit of designing for backwards compatibility for when we modify the authentication protocol in the future. Example:

"appsData": {
   "v1": {
        /* version 1 stuff goes here */
    },
    "v2": {
        /* version 2 stuff goes here */
    },
}

I would add that in implementing this, we should extend the key derivation path to use the full hash160 of the app name.

Agreed 100%.

Also, note that we won't be able to detect and apply backwards-compatibility fixes for single-player applications without some additional measures.

I think this could be addressed with a flag in the manifest.json. If the app developer is using this protocol or a future protocol, then the manifest.json would need to indicate an explicit version of the authentication protocol to use. If it doesn't, then we assume that the app wants the authenticator to do what we do today.

@yknl

This comment has been minimized.

Copy link
Collaborator

commented Mar 5, 2019

I think this is great, it will be one step closer to replacing DNS completely with BNS.

The minimum age of the manifest.json

What is the reason for having a minimum age for the manifest.json?

Also should we register a name space for apps?

@jcnelson

This comment has been minimized.

Copy link
Member Author

commented Mar 5, 2019

What is the reason for having a minimum age for the manifest.json?

The manifest.json now identifies mutable information, including the application's origin. If the app developer updates their manifest.json, it's possible that a client will see a stale version. Having the app developer pass in the expected creation-date of the manifest.json to the authenticator ensures that the authenticator detects a stale manifest.json. The app developer would deploy an updated version of the app with the newer timestamp whenever the manifest.json contents changed.

An alternative (possibly stronger) mechanism would be for the app developer to pass the cryptographic hash of the manifest.json in the auth request. It would achieve the same ends -- if the developer changes the manifest.json, they also need to change the app's signin handler to ensure that users don't accidentally fetch and process a stale manifest.json.

Also should we register a name space for apps?

We can do this, but any BNS name will work. However, I would be open to further refining this spec to require the BNS name to not have an expiration date -- i.e. you couldn't use a .id name to register an app, but you could use a .blockstack name. You could use also use a subdomain.

@kantai

This comment has been minimized.

Copy link
Member

commented Mar 5, 2019

An alternative (possibly stronger) mechanism would be for the app developer to pass the cryptographic hash of the manifest.json in the auth request.

I thought about something similar -- just having the app pass the manifest.json contents themselves during the auth request -- but I think that it would require a kind of strange build pattern and might be a pretty frequent stumbling block for developers. It seems easier to have the auth request pass a "manifestNewerThan" with a timestamp. So by default, the blockstack app generator would just initialize that with the current date, and things would mostly work out until the developer wanted to force a revocation, in which case, they'd just need to update one field.

We can do this, but any BNS name will work. However, I would be open to further refining this spec to require the BNS name to not have an expiration date -- i.e. you couldn't use a .id name to register an app, but you could use a .blockstack name. You could use also use a subdomain.

That's interesting. Maybe in V1 of this scheme, we require a non-expiring name. Otherwise, I think we'd want to detect and prevent the case where a name expires, is renewed, and the app key can be taken by the new owner, which for V1 would probably complicate the auth flow too much.

@jcnelson

This comment has been minimized.

Copy link
Member Author

commented Mar 5, 2019

just having the app pass the manifest.json contents themselves during the auth request

This would be risky -- the resulting auth-request URL might be too long for some browsers.

So by default, the blockstack app generator would just initialize that with the current date, and things would mostly work out until the developer wanted to force a revocation, in which case, they'd just need to update one field.

The fact that the app generator would need to be involved in this process makes me like the idea of passing a timestamp a lot more than passing a cryptographic hash.

That's interesting. Maybe in V1 of this scheme, we require a non-expiring name. Otherwise, I think we'd want to detect and prevent the case where a name expires, is renewed, and the app key can be taken by the new owner, which for V1 would probably complicate the auth flow too much.

Yeah, the more I think about how to handle renews and re-registers, the less I like the idea of dealing with expiring app names. I don't think making app names expire and have to be renewed is justified, since there are way more BNS names available than DNS names, when counting all the namespaces that could be created (and subdomain registrars and namespace creators can prevent squatters from consuming all the "good" names). I'm in favor of disallowing expiring names for apps.

EDIT: accidentally closed

@jcnelson jcnelson closed this Mar 5, 2019

@jcnelson jcnelson reopened this Mar 5, 2019

@friedger

This comment has been minimized.

Copy link
Collaborator

commented Mar 5, 2019

The proposed extensions to the manifest.json are not conform to the W3C standard. It is recommended to prefix new properties with a vendor prefix.

@larrysalibra

This comment has been minimized.

Copy link
Member

commented Mar 21, 2019

This is a great proposal @jcnelson

I'm interested in being able to sign in to apps without having to make additional network requests to servers controlled by the developer. (ie. the manifest.json file)

Can we put application origin info in the Atlas zone file instead of an external file like profile.json or manifest.json?

Removing the need for manifest.json files would give us some benefits:

* Privacy: users no longer have to make requests to an app developer controlled server to sign in. This opens up the ability to make apps that after you download them the first time can be cached and don't need to make requests back to the developer's servers.
* No more CORS headaches: developers no longer have to spend time figuring out how to set proper CORS headers in both their developer and production environments so that manifest.json works
@mehmetkose

This comment has been minimized.

Copy link

commented Mar 21, 2019

2 questions, users Gaia data are signed with app origin? if so, how we can access and migrate after we switch over BNS included manifest files?

@jcnelson

This comment has been minimized.

Copy link
Member Author

commented Mar 21, 2019

Can we put application origin info in the Atlas zone file instead of an external file like profile.json or manifest.json?

Definitely! If the application includes its Origin information and manifest.json information in the Atlas zone file, it should be used instead of anything learned through a network request.

@zone117x

This comment has been minimized.

Copy link
Member

commented Mar 21, 2019

@jcnelson Sounds like manifest.json info in Atlas is the way to go? If so should we update the proposal?
Also, what is the priority for this? (And estimated time you think it might take?)

@larrysalibra

This comment has been minimized.

Copy link
Member

commented Apr 3, 2019

Also, what is the priority for this? (And estimated time you think it might take?)

Same question!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
8 participants
You can’t perform that action at this time.