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

Authentication Scheme #134

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
221 changes: 221 additions & 0 deletions authentication-scheme.mediawiki
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
<pre>
NEP: <to be assigned>
Title: Authentication Scheme
Author: Erik Zhang <[email protected]>
Type: Standard
Status: Draft
Created: 2021-03-19
</pre>

==Abstract==

This NEP describes a scheme for third-party applications to authenticate users based on NEO.
The third-party applications mentioned here can be any type of application, including Dapps, websites, games, etc.

==Motivation==

Usually, an application saves user data on its own server. The authenticated user can modify the corresponding data through application-defined logic.
Traditional Internet applications usually use an authentication scheme based on username and password, which is not suitable for blockchain.
This authentication scheme allows third-party applications to authenticate users based on digital signatures.
In this way, NEO users can log in to any third-party application that supports this scheme without registering, and allow applications to share user data on the blockchain.

==Specification==

===Payloads===

The authentication process is divided into two steps.
In the first step, the server sends a challenge payload to the client to request authentication.
In the second step, the client sends the response payload to the server to complete the authentication.
The payloads are transmitted in the form of JSON.

====Challenge payload====

<pre>
{
"grant_type": "signature",
"allowed_algorithms": ["ECDSA-P256"],
"network": 5195086,
"nonce": "13458238842203010919",
"timestamp": 1616131368,
"callback": "https://someurl.com/callback"
}
</pre>

=====grant_type=====

This field should be fixed to <code>"signature"</code> and can be extended in the future to support more authentication schemes.

=====allowed_algorithms=====

An array containing the signature algorithms allowed by the server.

The client should use one of the algorithms to sign the response data.
If none of the algorithms are supported by the client, the authentication fails.

=====network=====

The magic number of the network.
Indicates which network this authentication will be applied to.

=====nonce=====

A 64-bit unsigned integer used to identify this authentication.

The server should record the expiration time of the nonce and check it when the response is received.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This requires the authentication server to be stateful. That could be avoided by including a signature for the nonce and timestamp in the request (and requiring that the client provide the signature in the response).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the server is stateless, how to identify the clients?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

State will definitely be needed to provide any useful authorization (e.g. a table mapping from Neo address to roles and/or other application-specific identity data). I'm just showing an opportunity to remove a database table and to avoid a database write on the initial authentication request (which could become a vector for unauthenticated denial-of-service).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the server does not record the nonce, it will become reusable. We need a mechanism to ensure that when a client is successfully authenticated, the nonce is immediately invalidated.

Copy link
Member

@djnicholson djnicholson Apr 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to mention here that the server is required to prevent nonce re-use:

When the server receives the response, it should check whether the nonce has expired. If the nonce has expired or not exists, the authentication fails.

It's currently not clear that this is required and a server implementor might choose to delete a nonce after successful use rather than invalidate it. I'm also curious as to why preventing nonce re-use is required (what security property breaks if the server doesn't do that?)

I'd still lean towards having the nonce invalidation happen post-authentication though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example, I log in to a website by scanning a QR code. If the nonce can be reused, the second person who scans the code will kick my login.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It sounds like the nonce is being used as a session ID? If that is the case there is a vulnerability: Anyone who has observed the QR code can later hijack the session (it wouldn't be safe to use this flow in a room with security cameras, for example).

To mitigate this, the nonce should be swapped for a session ID and this swap should only be allowed to happen once (note that there is still a race condition where an attacker can steal the session, though--to prevent that you need some sort of communication channel from the phone back to the browser).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The nonce is a one-time random number. There should be a nonce to sessionId mapping table on the server side.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This requires the authentication server to be stateful.

This is an interesting point @djnicholson, I need to study more on authentication. But perhaps, one way of not storing these nonces is to have some good pseudo-random algorithm, such as mersenne twister on server, starting with some secret seed, and then strongly hash mersenne twister outputs (via SHA-256, for example) to generate the nonce. The good thing is that, as long as some timestamp is involved, server can re-execute seeding process to find the nonce, instead of storing it. The bad thing is that, as soon as seed is leaked on server, nonces could be predicted.
Is it Neo servers or other servers that require being stateful?

The expiration time is recommended to be 5 minutes.

=====timestamp=====

The timestamp of the server.
This timestamp is used by the client to check whether the local time is synchronized with the server.

If the local time of the client is not synchronized with the server, the authentication may fail.
In this case, the client should first synchronize the time or prompt the user.

=====callback=====

''Optional''. An url that used to send the response payload.

When a <code>callback</code> is provided, the response payload is sent to the <code>callback</code> url in HTTP POST method.

====Response payload====

<pre>
{
"algorithm": "ECDSA-P256",
"pubkey": "0355912bc4e61c9715c5912397ea53a5ac6c103c4893fbd9c2a9f3be13b7a3e29d",
"address": "NfMFWYxaUUQy9SYo6AhRiGmRxfPxe9Edj7",
"nonce": "13458238842203010919",
"timestamp": 1616131369,
"signature": "BAS7Ljufj3vrhOrTAi21D/5Cf62n4r64Suf/do8dq/OCMHiLJl+hLJeMFZwTajVjhcpFLz6FuSEp13vvEqWf1w=="
}
</pre>

=====algorithm=====

The algorithm used by the client to sign the response data.
It should be one of the values in the <code>allowed_algorithms</code> sent by the server.

If the algorithm used by the client is not supported by the server, the authentication fails.

=====pubkey=====

The public key used to verify the signature.
It must correspond to the <code>address</code>, otherwise the authentication fails.

=====address=====

The address of the user to be authenticated.
It must correspond to the <code>pubkey</code>, otherwise the authentication fails.

=====nonce=====

A 64-bit unsigned integer used to identify this authentication.
This value must be exactly the same as the <code>nonce</code> sent by the server.

When the server receives the response, it should check whether the nonce has expired.
If the nonce has expired or not exists, the authentication fails.

=====timestamp=====

The timestamp of the client.
This timestamp is used by the server to determine the time of the signature to prevent replay attacks.

=====signature=====

The signature of the response data.
It should be encoded in base64.

====Response data to sign====

{| class="wikitable sortable" style="width: auto; text-align: center; font-size: smaller; table-layout: fixed;"
!Name
!Type
!Offset
!Size
!Description
|-
| network
| uint32
| 0
| 4
| The magic number of the network
|-
| nonce
| uint64
| 4
| 8
| The nonce sent by the server
|-
| timestamp
| uint32
| 12
| 4
| The timestamp of the client
|-
| hash
| uint160
| 16
| 20
| The script hash of the user's address
|}

===Scene modes===

====QR code mode====

A website can allow NEO users to log in directly.

The login process is:

#The user clicks the login button with the NEO icon.

#The QR code for login is displayed on the webpage. The challenge payload is encoded in the QR code. In this case, the <code>callback</code> must be included.

#The user opens the mobile wallet and scans the QR code.

#After the wallet recognizes the QR code, a pop-up window asks the user to confirm login.

#If the user cancels the login, the authentication process ends. Otherwise, go to the next step.
Copy link
Member

@chenzhitong chenzhitong Apr 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How the server gets the authentication refused/cancel message? Add State in Response data, include scaned, confirmed, refused, to optimize user experience?

Copy link
Member Author

@erikzhang erikzhang Apr 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the authentication is cancelled, the server won't receive the response payload. So nonce has an expiration time, and it is recommended to be 5 minutes.


#The wallet sends the response payload to the <code>callback</code> url through the HTTP POST method.

#After the website receives the response payload and the verification is successful, it notifies the front end to refresh the page.

#The authentication is complete and the login is successful.

====Plug-in mode====

If the user uses a plug-in wallet, it will be able to automatically log in to the supported website.

The login process is:

#The front end of the website detects whether a supported plug-in wallet is installed.

#The front end requests challenge payload from the server.

#The front end calls the <code>authenticate</code> method of the plug-in wallet and passes the challenge payload as a parameter.

#The plug-in automatically selects an account, or the user specifies an account for the authentication process.

#The wallet sends the response payload as the return value of the <code>authenticate</code> method to the front end.

#The front end verifies the response payload and notifies the server.

#The authentication is complete and the login is successful.

====Connection mode====

This authentication scheme can also be used in connection mode. For example, game clients, command line wallets, etc.

The login process is:

#The client connects to the server.

#The server sends the challenge payload to the client.

#The client sends the response payload to the server.

#If the authentication is successful, then keep the connection and continue the business logic. Otherwise, send an error code and disconnect.

==Implementation==