-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Rename Amount Field to DeliverMax (to prevent incorrect handling of Partial Payments) #3484
Comments
maybe add a new transaction type “PartialPayment” dedicated to partial payment. |
A name change would impact the whole ecosystem and a transaction type change could lead to not accepting partial payments because they are rare anyways so not seen worthy to implement. I honestly have very little sympathy for someone implementing something in their closed-source code clearly without reading the documentation (PartialPayments are one of the first items on "How to list XRP as an exchange") or engaging in any way with the developer community (other than getting probed and hacked by black-hat developers apparently). How many exchanges are actually impacted by a change vs. by partial payments ("multiple" or "numerous" can be 2 or 3...)? There are a lot of other things in the protocol that are not intuitive at all and that don't have easily visible solutions (trustline QualityIn/Out comes to mind...). Lastly, if you want such a change, you can already do it easily (similar to how xPring acts as a middleware): Write a proxy that forwards requests/answers to/from |
One of your recommendations (renaming the I explored several possibilities along those lines a couple of years ago. Take a look at these: https://github.com/nbougalis/rippled/commit/52d04bfcb0f63ffad58fdd495c036497c78f695c I think that we should revisit this issue; the above should be fairly easy to rebase, and they are both fairly straight forward. @carlhua, any thoughts? |
Reading the documentation should be expected of anyone working as a developer for an exchange, but vulnerable exchanges keep popping up and it's time to do something about it. I prefer: https://github.com/nbougalis/rippled/commit/52d04bfcb0f63ffad58fdd495c036497c78f695c Making partial payments off by default would probably take away most of its utility though. Depending on the current use, it might be wiser to remove partial payments completely. |
I think it would be a shame to block receiving partial payments by default. Removing Partial Payments: even a bigger shame. If the problem is that exchanges/devs (who didn't RTFM) look at the "instruction" (being the Amount field) instead of the tx outcome, I'd say renaming the Amount field for partial payments would make most sense to me. That way faulty implementations will simply look at a field that doesn't exist, which (if the implementation is even ignoring errors) effectively is "0". That'll protect hem. Eg. |
If we don't want to take away its utility, I agree that our best option is to rename the field. |
@RareData Maybe even P.S. (Re: my previous comment) My problem with removing partial payments isn't only the fact that I actually like the feature: it's also that a matter of principle: if we start removing all potential interesting features because a few people don't RTFM, where does it end? |
totalitarian nanny coin |
|
Speaking to the scope: I've seen 4-5 successful attacks within a month, all on new implementations, but ranging from small to big VASPs. There's a couple of entities constantly probing new implementations, and they often discover implementations faster than they're identified by bithomp, xrpscan, or xrplorer. Even though it is not a bug/exploit in the XRPL directly, that's not necessarily the way it is communicated by exploited entities, indirectly damaging the reputation of the XRPL. So while I agree with MarkusTeufelberger and have very little sympathy for implementers not reading the documentation, I also think that it's on due time to reconsider, if anything can be done to prevent future bad implementations, in the least intrusive way possible. I like the idea of renaming the Amount field to |
@MarkusTeufelberger |
I'll throw another suggestion into the mix: |
4-5 successful attacks per month consistently or did just a lot of particularly incompetent players show up recently (who don't even follow basic accounting practices, such as balancing their books...)? As I already said, the least intrusive way would be to filter out this field and/or replacing it in middleware instead of changing the lowest-level API available. One of the issues is probably anyways that potentially a lot of these vulnerable entities use the public servers supplied by Ripple, not running their own infrastructure. So a good first step could be to filter out this field from any response from |
Consistently and surprisingly many big name exchanges/developers/projects. |
Yet they are not named, not even in this ticket... Maybe a list of these many big name people would help to draw some attention to the issue from people that re-implement something for the nth time in their closed source corporate environment? |
I do not have long-term data at hand, but no, not consistently 4-5 per month. It should, however, be compared to the number of new exchange implementations. I don't think it makes the concern less valid though: many “implementers” do not read the documentation. I think affected parties can easily be running their own nodes, in which case filtering on public nodes will not have an effect. |
Well, I can name at least R3's Corda Settler that I helped patch in 2019. Thomas and Wietse have helped patch numerous others, not sure they can/want to name them publicly. |
We tested over 100 exchanges, about half of them were vulnerable and credited the proposed XRP in the |
woaaaah
ripple is one of those things that even when you're working on it full
time, you can confuse yourself
any efforts to make it simpler/more foolproof (without sacrificing
features) is probably a "Good Thing TM"
|
Then I'm unsure if changing a field and breaking the API for the entire ecosystem would be enough to fix this systemic issue. "Oh, |
@MarkusTeufelberger can you point me in the direction of that please? "Oh, Amount is now named MaxAmount or whatever on some transactions starting with 1.7.0? Let's just add that..." Is that a patch some where? Thank you kindly. |
One additional thing to consider is complexity of XRPL client logic, by renaming this field with a cutoff rippled / ledger version, clients that need to handle historical ledgers will have to have yet another special edge case for before/after this patch is applied. I feel a flag to block partial payments as implemented in nbougalis@52d04bf is a good tradeoff and would go even further to recommend that partial payments are disabled by default. The logic being that if exchanges / other endpoints don't explicitly implement logic to handle the partial payments edge case they are vulnerable, disabling this flag (enabling partial payments) would simply be one additional step ontop of addressing the issue. |
If a partial payment flag is introduced for accounts and it is disabled by default, the entire partial payment feature might just as well be deprecated, in my honest opinion. In many of the cases where partial payments are beneficial, the receiving entity will not be aware that they received a partial payment – this could e.g. be in cases where a regular user is doing a market sell/buy to swap currencies. |
Accounts should be allowed to receive partial payment by default, just explicit the transaction is partial payment , so I prefer to add "partialpayment" transaction. |
This sounds like a "have your cake and eat it too" situation. If the user wants to leverage partial payments but is not aware of it, they are potentially exposed to the original vulnerability where amount != partial payment amount. By requiring the user to explicitly "opt-in" to partial payments, the feature can be supported but with the explicit authorization of the end-user. Explicit PartialPayment transactions could work but is also another edge case / logic fork clients would have to handle. With the flag / functionality disabled by default, clients could ensure their application handles delivered_amount vs amount, enable the flag and then forget about it. |
The users who are potentially affected by the bad implementation bug is virtual asset service providers that maintain a separate ledger to keep track of their users' funds, where an average user has an account and uses a software or hardware wallet to sign and submit transactions. The average user will never be directly affected by the vulnerability that arises from not balancing the books and the technical obstacle of understanding flags and partial payment will keep them from using the feature, which will lead to fewer clients (software wallets etc.) implementing a feature to do partial payment-powered currency swaps, effectively killing the feature. It should be solved in a way that doesn't make the learning curve any steeper for average users. I think that renaming the field in an API-level would solve most problems without anyone noticing a disruption of service unless they were in actual danger:
It would be interesting to look at how much the feature is actually used, as I think it is mainly used for exploits and arbitrage circular payments. |
Note the new field output field in API will be named |
The draft PR is #4733 (comment) (unfinished, design could change, link pointing to comment on what I am actually doing) |
This change will only impact It could be argued that |
@intelliot there's a subtle problem with change as proposed in my draft PR and I want to discuss it here. The way it's currently written, the user cannot pass both Ways out I can see are:
The last option is clearly a breaking one, so we can write it off. Of the remaining two I think first is preferable. What's your opinion ? |
Agreed. "allow both fields on input, as long as they are identical" sounds good to me. |
I don't have a strong opinion, but I think allowing identical fields on input is preferable to not outputting the field at all. However, I don't see where there would be any necessity for making a round trip in the first place. A validated transaction is never going to be valid input anyway, so disallowing it is almost a feature. Is there another input case I'm not considering? |
I wouldn't be surprised if some users were relying on the ability to roundtrip (less some, well specified, fields) for test purposes. |
Agreed on both points - I don't think we make any guarantee that it is valid to roundtrip the API response, but it is also nice to keep that in place since it isn't too painful to do so. In other words, go with "allow both fields on input, as long as they are identical" |
Using the "Amount" field in Payment transactions can cause incorrect interpretation. There continue to be problems from the use of this field. "Amount" is rarely the correct field to use; instead, "delivered_amount" (or "DeliveredAmount") should be used. Rename the "Amount" field to "DeliverMax", a less misleading name. With api_version: 2, remove the "Amount" field from Payment transactions. - Input: "DeliverMax" in `tx_json` is an alias for "Amount" - sign - submit (in sign-and-submit mode) - submit_multisigned - sign_for - Output: Add "DeliverMax" where transactions are provided by the API - ledger - tx - tx_history - account_tx - transaction_entry - subscribe (transactions stream) - Output: Remove "Amount" from API version 2 Fix #3484 Fix #3902
I have a question pertaining to the inclusion of "DeliverMax" field. Why is it included in As per an earlier comment (#3484 (comment)), Additionally, the The PR implementation adheres to the specification, I'm trying to understand the rationale behind the specification. |
As mentioned in #3484 (comment), it's nice that the transaction JSON can roundtrip - i.e. you can take a response (output), perhaps make some changes, and then submit it as a new transaction.
I'm not sure what you're trying to say here - what's the relevance or significance? |
You missed that these methods only accept both This allows round-tripping; since these methods return the body of the signed transaction, we want to allow that body to be usable in a similar context (less some well-defined fields), e.g. for test purposes. The important point here is that thanks to this decision, users can switch to use |
@Bronek Thanks for the reference. I have modified the [Note: The above unit tests throw an error at https://github.com/ckeshava/rippled/blob/01fdbf43813e9adafb4041e7fb58a38c22e0fe4b/src/ripple/protocol/impl/STParsedJSON.cpp#L106 ] This PR inserts the alias in the |
@intelliot I'm trying to understand: Apropos API inputs, does this PR update all Payment transaction API inputs or is this relevant only to the inputs of I understand the implications of API responses well. The client library code has a tight coupling between the input to a general |
You will notice that the stack trace of the failing tests looks something like this
This is because
I do not think 2nd or 3rd option are worth the trouble. |
All the uses of |
Thanks for the explanation Bronek, the distinction between I'm working on updating the client libraries to support the
As it stands, this PR does not modify these files.
From the perspective of updating client libraries, It would be very convenient if we could do Option-3, but I get that it's a lot of work. |
WebSocket is different only in these two areas:
The actual implementation of all methods is done by the same
Since all client API requests go through
Yes, and they are right not to make such distinction, as I explain above. PS. I was wrong scoffing |
Okay, I get your point. It still leaves the below problem open.
The other alternative is to modify the parsing of |
As @Bronek mentioned, the aliasing is handled at the |
Hmm right, I'm wondering if it's lesser technical debt to update the protocol, instead of maintaining this alias change across C++, Python and Javascript client libraries. Anyways, thanks for the explanation |
We "only" need to maintain it as long as we support API version 1. No idea how long that would mean in practice (several years ?) |
Additionally, there is a bunch of functionality that is already maintained across different libraries. I don't see this as much different. Serialization itself is an example. |
…F#4733) Using the "Amount" field in Payment transactions can cause incorrect interpretation. There continue to be problems from the use of this field. "Amount" is rarely the correct field to use; instead, "delivered_amount" (or "DeliveredAmount") should be used. Rename the "Amount" field to "DeliverMax", a less misleading name. With api_version: 2, remove the "Amount" field from Payment transactions. - Input: "DeliverMax" in `tx_json` is an alias for "Amount" - sign - submit (in sign-and-submit mode) - submit_multisigned - sign_for - Output: Add "DeliverMax" where transactions are provided by the API - ledger - tx - tx_history - account_tx - transaction_entry - subscribe (transactions stream) - Output: Remove "Amount" from API version 2 Fix XRPLF#3484 Fix XRPLF#3902
There are numerous examples and it is even documented in the XRPL docs that using the "Amount" field in a partial payment can cause incorrect interpretation of transactions. There also have been numerous documented accounts XRPForensics has provided multiple examples before.
What I would like to suggest, although it would be a large undertaking, is renaming the "Amount" field to something more descriptive.
Like "possible_amount_delivered".Link to existing doc and field referenced https://xrpl.org/partial-payments.html#partial-payments-exploitThis would probably require a deprecated flag on this function. Documentation changes, along with a slow roll out. Over multiple releases.
The reason I flip this requirement back on to the XRPL is that there continue to be numerous cases that arise from this issue. A simple field name change would "fix" all newer implementations of this.
The text was updated successfully, but these errors were encountered: