The current SPSP payment structure has no notion of authentication. This means anybody can push or pull value to or from an SPSP endpoint if the particular endpoint is known. While one can argue that this is a feature in the case of push payments (anonymous payments), it is definitely not acceptable in the case of pull payments from a security perspective (I’m happy to be proven wrong because what I’m about to propose is more complicated ). I’ll recap the current flow using the wallet use case and outline the problems.
Current architecture
The wallet runs an SPSP server that keeps track of users’ balances. Each user has their own payment pointer to which they can receive money, e.g.
- Alice’s payment pointer: $wallet.com/alice
- Bob’s payment pointer: $wallet.com/bob
If Bob wants to send money to Alice, he queries their endpoint to receive a destination account and shared secret, connects to this account via STREAM and sends packets.
However, Alice does not know where those packets are coming from.
In the case of pull payments, Company requests a pull payment pointer from Alice which they would have to create using the wallet interface. It would look like this:
Company can query this endpoint, which is a special one for pull payments and this particular pull payment agreement, create a STREAM connection and receive value.
However, consider Devil to be a malicious user trying to pull money. They could just brute-force try different combinations of $wallet.com/username/uuid and would probably find a working endpoint they could exploit. While I agree that this is unlikely, $wallet.com/username/uuid could also be exposed to an ISP in case of a DNS leak.
I’m not an expert on wallet laws but I fear that these are risks that wallet providers are not willing to take.
Proposal: Authorized payments
Alice has one payment pointer for everything, it is their identity within wallet.com: $wallet.com/alice. Nobody can query, push or pull money without an access token. A GET request to $wallet.com/alice without a token (access or refresh) will start an oauth flow as depicted in the figure below. The GET request needs to contain the scope of the preferred action (query, push or pull, where push and pull include query).
Push flow
- GET request from Company to $wallet.com/alice
- Scope: push
- Parameters: sending entity = Company
- Wallet authenticates Company somehow (This part is still a bit unclear. It could be something wallet specific, i.e. Company needs to register with Wallet, or something broader. I am not an expert on this topic…)
- (Alice may be asked to agree to push to her account)
- Wallet returns access token including scope
- GET request from Company to $wallet.com/alice including the access token
- Returns destination account and shared secret
- Company connects to Wallet using destination account and shared secret
- Company opens a stream connection
- Company sends the access token via data stream
- After verifying token, the wallet sets
receiveMax
- Company streams money to Alice’s account
Alice can be sure that she is not receiving dirty money because there is a valid token sent with every request. In the case of querying the endpoint, which are steps 1-6, Alice can be sure that nobody receives her STREAM details. I don’t give my bank details to anyone either.
Pull flow
- GET request from Company to $wallet.com/alice
- Scope: push
- Parameters: sending entity = Company, pull payment agreement
- Wallet authenticates Company somehow again
- Wallet returns access token including scope and agreement
- GET query request from Company to $wallet.com/alice including the access token
- Returns destination account and shared secret
- Company connects to wallet using destination account and shared secret
- Company opens a stream connection
- Company sends the access token via data stream
- After verifying token, Wallet starts streaming value to Company
Company needs to be authenticated by Wallet and especially pull payments need to be authorized by Alice. One could maybe even omit step (3) in my figure (authenticating Company) or make it optional if Alice needs to authorize incoming and outgoing payments. We can argue that Alice can make informed decisions on whether she wants to receive money from Bob or allow Company to pull. If she is shopping in a known online store, she can be quite certain that the request for pull pointer that is popping up on checkout is legit.
How could that work with Codius?
We wanted to enable pull payments in Codius such that pods are automatically extended. This requires a pull payment pointer when a pod is uploaded. Since there is no fully developed GUI for it (yet, at least not that I know of), there can not be a nice little popup to authorize the payment. However, Wallet could allow for pre-generation of access and refresh token on their platform that one has to copy. Let’s face it: At the moment, you have to know your stuff to upload to Codius anyway .