Building applications that listen for Stellar payments
A main feature of the bx8.io website was to display payments made by a participant to any of our deposit addresses.
We first display an address, and a memo they can use when sending a payment.
A memo on a Stellar payment is used to “tag” that transaction. Memos are meant to semi-identify the person/entity making the payment, outside the blockchain’s context. They’re useful when viewing payments made to an address, you’ll know which transactions came from who.
Once a payment is sent with the memo, displaying payments on the relevant user’s dashboard should be fast. Stellar transactions are quick. It will be uncharacteristic of our application if users wait more than a minute to see transactions reflect on the website. To display payments, we’ll need to make our application “listen” on Stellar.
Listening for Payments
In order to make an application listen for Stellar payments, Stellar provides an application called Horizon that you can run on your own servers. Horizon provides an interface where applications can integrate with the Stellar blockchain.
With Horizon, getting the list of payments on an account every X seconds or minutes might be the easiest method to listen for payments.
Although, instead of polling, Horizon has an option that allows us to achieve “instant display”. We can stream payments for a specific account if we add the text/event-stream
request header when getting the list of payments from an account.
Writing the code to accept the stream, handling failures, and keeping tabs of the cursor
would take effort, but it’s not without its rewards. You keep your application simple, apart from the Horizon dependency.
Another option beyond writing code would be to use Stellar’s Bridge Server. You can run it on your own servers, and configure it to listen for payments to an address. Once a payment is made to an address it makes an HTTP POST
, a callback, to an HTTP endpoint of your configuration.
Protecting the callbacks endpoint
When you use the Bridge Server, it means your application will have a callbacks endpoint to listen for payments.
This allows for potential abuse. You risk enabling bots or people to post fake transactions of any kind to that endpoint. Your application might get confused with what is from the blockchain and what is fake.
With this in mind, it means we’ll have to think of ways to secure this endpoint. When mulling about security, it’s good to think in layers.
Should you put more logic on the application layer? Should we enforce stricter record uniqueness on the database layer? What about options in restricting access via the network layer? How about validating authenticity of application-related payloads against another node in the blockchain?
Here are some thoughts on securing the callback endpoint:
1. Make the application a “smart listener”
Whether you use a callback endpoint or listen to Horizon for payments, your application needs to be a “smart listener”.
Once a transaction is “listened” and “recorded” by an application, it should keep tabs of it. Transactions on the Stellar blockchain are immutable, so we shouldn’t think about tailoring code to expect changes. If the application, or your callback endpoint, receives a transaction of the same ID, it shouldn’t recreate it. This sort of behavior is called “idempotence”.
Make the code on the callback endpoint “idempotent”.
2. Configure Stellar Bridge Server to use a mac_key
This makes Stellar Bridge Server send an additional header to its payloads on our callback endpoint. The header is called HTTP_X_MAC_PAYLOAD
. The header contains the value of the configured mac_key
on its config file. You can then check for callbacks with that header, and if its value is the same on the config file.
3. Validate callback authenticity by checking callbacks against a Horizon server
There are some cases where it is insufficient to accept callbacks even if the HTTP_X_MAC_PAYLOAD
is verified. If someone knew your Stellar Bridge server and decided to impersonate it, providing the same mac_key
and all, this makes your application vulnerable.
Though highly unlikely to happen, it is still important to mitigate this risk. One way to circumvent an impersonating bridge server is to check an incoming callback against the Stellar blockchain. You can query another Horizon instance, check if the incoming payload actually exists and compare if they have the same contents (amount, source address, memo, asset_type, etc.)
Displaying blockchain payments on an application might be a simple task, but it’s worth thinking how your applications should securely listen to the blockchain. I hope this post has inspired you to think about security when building blockchain-based applications, even ones that simply read from it.
If you’re using Rails to build an application that listens for Stellar payments, we built a rails engine that makes Rails apps securely listen for callbacks coming from a Stellar Bridge server. https://github.com/bloom-solutions/stellar_base-rails