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

LUD-21: pinLimit for withdrawRequest - resolves #201 #200

Open
wants to merge 14 commits into
base: luds
Choose a base branch
from

Conversation

titusz
Copy link

@titusz titusz commented Feb 11, 2023

LNURL-withdraw is increasingly used for convenient contactless payments via NFC devices that do not require a battery and do not have a user interface.

While these devices can produce unique one-time LNURLw-links with replay protection there is still the risk of losing the device or maliciously scanning the device without knowledge of the owner.

This LUD seeks to improve security of tap & pay experiences by optionally requesting a second factor PIN for withdrawRequest callbacks.

@titusz titusz changed the title DRAFT - LUD-XX: pinLimit for withdrawRequest DRAFT - LUD-XX: pinLimit for withdrawRequest - resolves #201 Feb 11, 2023
@dipunm
Copy link

dipunm commented Jul 24, 2023

This is great. One thought though, I think there should be a way to provide a human readable response for failure.

The pin may be incorrect, it could be that the card is locked after too many attempts. These are good to tell the customer, but I guess it could be given covertly via their app too.

Not sure if a reason response has been discussed, what was the outcome?

@titusz
Copy link
Author

titusz commented Jul 27, 2023

This is great. One thought though, I think there should be a way to provide a human readable response for failure.

That is already possible as specified in LUD 03 section 6

LN SERVICE sends a {"status": "OK"} or {"status": "ERROR", "reason": "error details..."} JSON response ...

@titusz titusz changed the title DRAFT - LUD-XX: pinLimit for withdrawRequest - resolves #201 LUD-21: pinLimit for withdrawRequest - resolves #201 Aug 3, 2023
add Bolt Card Wallet & Bolt Card PoS with support for PIN LUD
@titusz
Copy link
Author

titusz commented Aug 3, 2023

I am happy to see that the "pinLimit for withdrawRequest" proposal is gaining some traction from the Bolt Card community. It has been implemented by https://github.com/boltcard/boltcard-wallet & https://github.com/boltcard/bolt-card-pos. I would love to see this merged.

@jimmydjabali
Copy link

@SwissBitcoinPay will also implement that in the coming weeks.

@kingonly
Copy link

kingonly commented Aug 6, 2023

  1. Is this solving a real problem? I mean I understand the theoretical problem, but is this a real world issue? Did users complain?
  2. Is this issue solved in regular OTC gift cards (e.g. Amazon etc)?
  3. Better to decide on a fixed digit pin (e.g. 4) if there's a brute force protection. The link shouldn't be invalidated after the first try. The UX is completely different (can be much much better) for a fixed digit than for a 4-15 digits number.

I'm really not sure about this one. This is a breaking change and need to better understand the motivation for doing it now.

@titusz
Copy link
Author

titusz commented Aug 7, 2023

  1. Is this solving a real problem? I mean I understand the theoretical problem, but is this a real world issue? Did users complain?

Yes, users are asking for it:

https://twitter.com/HOLLEPENJO/status/1675011134343069697
https://twitter.com/Patrick85950515/status/1669641879431036929
https://twitter.com/JustinFilson/status/1669409590625157121
https://twitter.com/styggen2/status/1666779214282883073
https://twitter.com/CaledonieCrypto/status/1664394950979751936
https://twitter.com/thecolinbrown/status/1582424854539939841
https://twitter.com/PlebPay/status/1582061142146310144
https://twitter.com/CoinCornerDanny/status/1669424518144704512

  1. Is this issue solved in regular OTC gift cards (e.g. Amazon etc)?

It is not meant for gift cards with a fixed budget but for contactless payment cards (Bolt Cards) that are connected to a users lightning node and can generate a potentially unlimited number of withdraw tokens.

  1. Better to decide on a fixed digit pin (e.g. 4) if there's a brute force protection.

I agree that 15 digits is probably a bit exzessiv. But 4 might be a bit weak for some use cases. Why not let the user/SERVICE decide on PIN security level.

The link shouldn't be invalidated after the first try.

Why? User could still retry with a new URL after a new scan. We could also let SERVICE decide the limit for invalidating a given withdraw URL.

The UX is completely different (can be much much better) for a fixed digit than for a 4-15 digits number.

Maybe we could specify 4-8 digits which are more realistic.

This is a breaking change and need to better understand the motivation for doing it now.

I wouldn´t call this a breaking change. Its an optional extension like LUD-19 and others. If a WALLET/CLIENT does not implement it the request to the withdraw callback to SERVICE may return an error with for example "PIN required for amount above x.y"

@kingonly
Copy link

kingonly commented Aug 7, 2023

These references don't suggest a real issue (or real users). They suggest a potential issue which I agree exits. I'm still not convinced by the internal twitter discussions. We need to have a serious conversation about the motivation here. This change also goes against the payment simplication trend (tap to pay).

Designing a UI for 4 or 15 digits is very very different. The client can't accommodate the service AND provide a good UX for all cases. There's always a tradeoff which is unnecessary here. 4 or 6 I don't care (I don't understand why 4 isn't enough if the service has brute force protection), but it needs to be a fixed number if we want a good UX.

By breaking change I mean lnurlw will stop working even with an explicit error.

@kingonly
Copy link

kingonly commented Aug 7, 2023

Links shouldn't invalidated after the first try: because it's likely users will enter the wrong pin sometimes. Having them to rescan isn't ideal and doesn't exist in the other "enter pin" systems, so why?

@titusz
Copy link
Author

titusz commented Aug 7, 2023

By breaking change I mean lnurlw will stop working even with an explicit error.

Lets assume a user sets a pinLimit of 50k sats on SERVICE. Wouldn´t all payments below 50k sats still work even if CLIENT does not understand the optional pinLimit field?

@titusz
Copy link
Author

titusz commented Aug 7, 2023

Links shouldn't invalidated after the first try: because it's likely users will enter the wrong pin sometimes. Having them to rescan isn't ideal and doesn't exist in the other "enter pin" systems, so why?

I agree. 3 times try before invalidation is probably the most familiar to people. What would you recommend?

@kingonly
Copy link

kingonly commented Aug 7, 2023

By breaking change I mean lnurlw will stop working even with an explicit error.

Lets assume a user sets a pinLimit of 50k sats on SERVICE. Wouldn´t all payments below 50k sats still work even if CLIENT does not understand the optional pinLimit field?

Yeah, so the optional pinLimit is breaking 50k+ payments. What I mean is that it's not really optional. Clients will HAVE TO implement this is provide an operational service.

@kingonly
Copy link

kingonly commented Aug 7, 2023

I agree. 3 times try before invalidation is probably the most familiar to people. What would you recommend?

3 is ok

@PeterRounce
Copy link

PeterRounce commented Aug 7, 2023

This is not a breaking change as far as I can see.
The original lnurlw function is still there and this spec is fully backward compatible.
There is an extension of an amount that can be used where a PIN is entered.

Bolt card users have requested the PIN function as part of the Praia Bitcoin Brazil project and also in the https://t.me/bolt_card group.

It looks like the requirements from the LUD spec for listing are covered:

To be accepted, it just has to be generally decent and make sense and be implemented or currently being implemented by 2 or more wallets.

@kingonly
Copy link

kingonly commented Aug 7, 2023

This is not a breaking change as far as I can see. The original lnurlw function is still there and this spec is fully backward compatible. There is an extension of an amount that can be used where a PIN is entered.

Bolt card users have requested the PIN function as part of the Praia Bitcoin Brazil project and also in the https://t.me/bolt_card group.

It looks like the reqirements from the LUD spec for listing are covered:

To be accepted, it just has to be generally decent and make sense and be implemented or currently being implemented by 2 or more wallets.

I think I explained why I see it as a breaking change.
There are dozens of wallets now, not sure two wallets implementation suffices.

I understand you guys want this merged, and I think I'm well aware of what's going on in the ecosystem including the Praia project.

Yes, I'm being conservative with changes because I understand what it means to implement and maintain them. Feel free to ignore me, but I would advise you to try to provide some tangible data on what this is needed if you want to achieve some kind of a consensus.

Meanwhile, let's address the digit, retries and get more people to review this PR.

@titusz
Copy link
Author

titusz commented Aug 7, 2023

I updated the spec to 3 retries before link invalidation and set the pin length limit to 8 digits. I can also set a fixed number of digits (4, 5, 6?) for the PIN if there is consensus among reviewers.

I agree with @kingonly that it would be helpful to get more people to review this PR.

@kingonly
Copy link

kingonly commented Aug 7, 2023

I updated the spec to 3 retries before link invalidation and set the pin length limit to 8 digits. I can also set a fixed number of digits (4, 5, 6?) for the PIN if there is consensus among reviewers.

Fixed digit spec is simpler and will allow wallets to define a fixed UI which is easier for users. The alternative is to implement an open input field (or dynamic UI if the backend returns the digit number). This is what I'm thinking and I suggest to KISS. I don't see the value in a variable digit.

Screenshot_2023-08-07-22-51-56-94_73a31df444cba46df764485ac1a8c3ef

21.md Outdated Show resolved Hide resolved
21.md Outdated Show resolved Hide resolved
21.md Outdated Show resolved Hide resolved
@MichaelAntonFischer
Copy link

To add my two cents shared so far only on telegram:

I completely oppose this being added to the spec. Right now the merchants are barely tolerating the complexity of the offline payment pin.

If I now have to tell them that they need to train their staff that there can be two pins with exactly the same structure, but obtained by the user in two completely different ways, this will hurt adoption.

We need to find either a different solution for offline payments or for additional Boltcard security (is that even needed?).

And offline payments from our experience happens at least 1000x more than Boltcard, let alone big Boltcard payments that need a pin, so that functionality is more important I think.

@talvasconcelos
Copy link

talvasconcelos commented Aug 20, 2024 via email

@pieterjm
Copy link

Why the restriction to a four-digit PIN? As the possibility of an OTP scheme is mentioned in the document, a variable length PIN, like between 4 and 8 digits to allow compatibility.

@MichaelAntonFischer
Copy link

Counterproposal:

What is the use case of a PIN?

To prevent fraudulent use of a card.

What types of fraud can happen?

  1. Card stolen -> deactivate it
  2. Card copied -> impossible with ntag424
  3. Double booking by merchant -> rate limiting
  4. Merchant withdraws more than agreed -> transaction and daily max, pin would only help if expected payment was smaller than pin limit

In a nutshell, boltcards are already way better than credit cards and pins have very little added value.

So why don’t we work on better algorithms to detect and block suspicious transactions instead?

@arcbtc
Copy link

arcbtc commented Aug 21, 2024

Im with Mike, and much more into it being off spec server logic, being able to temp raise max spend. As well as more server logic for general security, again, off spec, that's how tap/pay works already.

I think security and ux is better, users being able to easily set max amount in the card host software rather than a pin. Going over maxspend is an unusual event, so doesn't need extra spec bloat.

Tap/pay with cards currently doesn't have pin UX, prob for good reasons.

@titusz
Copy link
Author

titusz commented Aug 21, 2024

Optional PIN support improves security in cases of lost or maliciously scanned NFC payment devices. In both cases the user may not be aware what´s happening and does not deactivate his/her card.

@titusz
Copy link
Author

titusz commented Aug 21, 2024

I think security and ux is better, users being able to easily set max amount in the card host software rather than a pin

NFC BotlCards and BoltRings support offline usage (on the user side). It´s about not having to have a mobile device or internet connection. How would the user change their card host settings on the go?

@MichaelAntonFischer
Copy link

I think security and ux is better, users being able to easily set max amount in the card host software rather than a pin

NFC BotlCards and BoltRings support offline usage (on the user side). It´s about not having to have a mobile device or internet connection. How would the user change their card host settings on the go?

But what improvement in security offers the pin? The thieve will be able to spend max transaction max daily limit regardless.

It might allow you to set slightly smaller limits that’s it. But then you have to trust the card reader not to log your pin, so you would need all the convoluted ineffective guardrails from the fiat system, certify pos devices, etc.

@arbadacarbaYK
Copy link
Contributor

I think security and ux is better, users being able to easily set max amount in the card host software rather than a pin

NFC BotlCards and BoltRings support offline usage (on the user side). It´s about not having to have a mobile device or internet connection. How would the user change their card host settings on the go?

But what improvement in security offers the pin? The thieve will be able to spend max transaction max daily limit regardless.

It might allow you to set slightly smaller limits that’s it. But then you have to trust the card reader not to log your pin, so you would need all the convoluted ineffective guardrails from the fiat system, certify pos devices, etc.

This is not the place to argue if a PIN makes sense for you. Dont use NFC on your device if you dont like it then. NFC card and PINs are a common UX and theres absolutely no reason to oppose common practices that users expect when being the card processor.

@arbadacarbaYK
Copy link
Contributor

arbadacarbaYK commented Aug 21, 2024

The fact that cards with a PIN and a UX for it is already out there without a standard being set is the reason why this PR exists.

NFC payments on offline devices dont work, Boltcards only work in online-mode.. If online the card-user knows he needs a pin. In offline-mode the device needs another pin by another logic (that you said you want adapted to prevent confusion). Communicate the difference on the display and address the changes for offline-mode.

@PeterRounce
Copy link

The PIN offers a second factor authentication.
"Something you know" as well as "something you have".

It can be used to set different payment rules. These can be more than just a per-transaction limit, although that makes sense as well as some kind of rate-limit.

In the situation where a user loses their card, the amount of funds at risk can be limited, even down to zero, if required.

It may be possible to discover a user's PIN by watching over their shoulder, with a camera or compromising the PoS device. My opinion is that these are fairly obvious and understandable risks that can be managed by the card user.

I don't see a downside other than a bit of added complexity, but this has been kept to a minimum.

@AaronDewes
Copy link

Here's my opinion on this proposal:

  • The response with an invalid PIN is not specified (Status code, ...)
  • Retry limit could be dynamic; retries remaining could be a property => This would allow the client to display it.
  • PIN length could be a property (Already suggested a few times)
  • A feature to do ratelimiting would be great too. For example, if an invalid PIN is entered 3 times, the server could respond to a next LNURL request from the same Boltcard with a rate limit warning. That could probably be a different LUD though. (Also suggested above already)

In general, I don't think a PIN entered on a separate device provides a major security benefit, so I don't like the idea, but the current spec would, if the idea is accepted, need these improvements in my opinion.

@arbadacarbaYK
Copy link
Contributor

arbadacarbaYK commented Aug 21, 2024

Here's my opinion on this proposal:

  • The response with an invalid PIN is not specified (Status code, ...)
  • Retry limit could be dynamic; retries remaining could be a property => This would allow the client to display it.
  • PIN length could be a property (Already suggested a few times)
  • A feature to do ratelimiting would be great too. For example, if an invalid PIN is entered 3 times, the server could respond to a next LNURL request from the same Boltcard with a rate limit warning. That could probably be a different LUD though. (Also suggested above already)

In general, I don't think a PIN entered on a separate device provides a major security benefit, so I don't like the idea, but the current spec would, if the idea is accepted, need these improvements in my opinion.

Retry limits / ratelimit needs to be done on the Boltcardhub/card issuer side. Theres already a deactivate-status implemented that is already mentioned above.
Statuscodes for certain errormessages would be great, pls see list above on the ISO mentioned for PIN-payments that we can start with. Agree that a proposal should be attached to the LUD for those.

Heres e.g. the changes proposed for LNbits which has both
Boltcardhub : lnbits/boltcards#21
POS terminal : lnbits/tpos#16

@titusz
Copy link
Author

titusz commented Aug 22, 2024

@AaronDewes

  • The response with an invalid PIN is not specified (Status code, ...)

LUD 3 point 6 is very specific about the response schema where status can be either OK or ERROR plus a free text reason field. I did not want to introduce conflict with LUD 3 by inventing new custom status codes. I´d like to keep this spec simple, but if that is something that people want, I am fine with it. Please feel free provide specific modifications to this proposal.

  • Retry limit could be dynamic; retries remaining could be a property => This would allow the client to display it.
  • PIN length could be a property (Already suggested a few times)

Again I wanted to keep it simple and only introduce one new field to the withdraw schema. But I am fine with both additions if there is consensus that they are needed.

In general, I don't think a PIN entered on a separate device provides a major security benefit ...

I would argue that the PIN offers major security benefits in at least 3 cases:

  • The user looses the devices with out noticing
  • The device gets stolen without the user noticing
  • NFC Skimming (scanning an NFC device without the owner's knowledge)

@dni
Copy link

dni commented Aug 29, 2024

my 2 cents is, i get the use cases and i kinda like the idea, but i think one issue with this that it should be in the withdraw response and not the request, this makes the flow kind of weird.

my proposal would be to have something similar like SuccessAction defined in LUD9 https://github.com/lnurl/luds/blob/luds/09.md.
i would call it PinAction with a property of the limit, error message, retries left, etc.
so it only takes affect after one withdraw request and when it fails the server decides to make a withdraw response with this new action. the frontend can then show a pin dialog and post the withdrawrequest again with a pin argument.

this would not so much disrupt the lnurl flow and also would be very similar to card payments today.

@dni
Copy link

dni commented Aug 29, 2024

maybe also a more general withdrawErrorAction with different types like pin, balance, etc.

@SwissBitcoinPay
Copy link

We have implemented it on https://github.com/SwissBitcoinPay/boltcard-tools-terminal thanks to the work of @X-Hades-X with SwissBitcoinPay/boltcard-tools-terminal#33

@zzzhan
Copy link
Contributor

zzzhan commented Oct 25, 2024

which wallet does support this?

@zzzhan
Copy link
Contributor

zzzhan commented Oct 25, 2024

We have implemented it on https://github.com/SwissBitcoinPay/boltcard-tools-terminal thanks to the work of @X-Hades-X with SwissBitcoinPay/boltcard-tools-terminal#33

it does not make sense, the pin is not encrypted or encoded.

@X-Hades-X
Copy link

@zzzhan The Boltcard Tools Terminal (https://github.com/SwissBitcoinPay/boltcard-tools-terminal) is a backend agnostic helper app. It simply can scan/read invoices, display the amount and description and will read the bolt card to pay for it.
Currently I'm adding support to create invoices with the bolt card, so you can also recieve with the app not just send.

Regarding encryption I was also confused why no requirements about hashing the pin or so exists. I figured HTTPS is enough since these things are probably self hosted and you own the server anyway. But if you know of a standard I missed I would be glad to know.

@zzzhan
Copy link
Contributor

zzzhan commented Oct 25, 2024

@zzzhan The Boltcard Tools Terminal (https://github.com/SwissBitcoinPay/boltcard-tools-terminal) is a backend agnostic helper app. It simply can scan/read invoices, display the amount and description and will read the bolt card to pay for it. Currently I'm adding support to create invoices with the bolt card, so you can also recieve with the app not just send.

Regarding encryption I was also confused why no requirements about hashing the pin or so exists. I figured HTTPS is enough since these things are probably self hosted and you own the server anyway. But if you know of a standard I missed I would be glad to know.

But there are some custody lightning wallets and services, it should be hashed before creating a pin. The pin protocol should be supported ASAP. I propose a pin hashed with the uid of card.

@PeterRounce
Copy link

The PoS has the PIN and the bolt card host server has the PIN.
Communications are HTTPS/TLS encrypted so it can't be seen en-route.
@zzzhan - what is the perceived need to encrypt it further, i.e. who are you protecting it from?

@zzzhan
Copy link
Contributor

zzzhan commented Oct 25, 2024

The PoS has the PIN and the bolt card host server has the PIN. Communications are HTTPS/TLS encrypted so it can't be seen en-route. @zzzhan - what is the perceived need to encrypt it further, i.e. who are you protecting it from?

The plaintext of pin is being stored in the third party services(custody lightning)

@titusz
Copy link
Author

titusz commented Oct 25, 2024

But there are some custody lightning wallets and services, it should be hashed before creating a pin. The pin protocol should be supported ASAP. I propose a pin hashed with the uid of card.

I agree that the pin protocol should be supported ASAP :)

Regarding PIN hashing/encryption:

The PIN is entered by the user on an untrusted payment terminal. Maybe I am missing something but I cannot imagine any way of preventing the leak of the PIN to the merchant without some closed hardware certification infrastructure on the terminal side (which I guess we don´t want).

The spec mentions the limitations: https://github.com/bitcoin-ring/luds/blob/withdraw-pin/21.md#security-considerations

Any suggestions on security improvements of the protocol are welcome.

@titusz
Copy link
Author

titusz commented Oct 25, 2024

The plaintext of pin is being stored in the third party services(custody lightning)

The protocol does not make any assumptions about how PINs are stored by SERVICE . It can very well store only hashes of the PINs or even implement some OTP scheme. At the protocol level we cannot verify how SERVICE handles PIN storage anyways so I would regard that out of scope of the protocol.

@X-Hades-X
Copy link

The plaintext of pin is being stored in the third party services(custody lightning)

Considering that you have enough trust in the SERVICE, if you let them custody your funds, it shouldn't be a problem that it is getting the pin in plain text. @titusz is right, the implementation of the SERVICE is free to store it plain or hashed in the database.

On the client side a leaky pin is probably the least of our problem. I would be more annoyed if people use PoS that show wrong values to be paid. Gametheory is probably the only thing that helps there.

@zzzhan
Copy link
Contributor

zzzhan commented Oct 29, 2024

The plaintext of pin is being stored in the third party services(custody lightning)

Considering that you have enough trust in the SERVICE, if you let them custody your funds, it shouldn't be a problem that it is getting the pin in plain text. @titusz is right, the implementation of the SERVICE is free to store it plain or hashed in the database.

On the client side a leaky pin is probably the least of our problem. I would be more annoyed if people use PoS that show wrong values to be paid. Gametheory is probably the only thing that helps there.

The basic principal is the pin or password should be encrypted or hashed when it is sent to the 'SERVICE'. It is the first step to make sure the leaky. For example, some finance APP will use a special keyboard to input the pin and get an encrypted pin.For trade-off , I propose to hash the pin with UID of the card.
BTW, the pin should not be fixed 4 digits, for a client it should be flexible for inputing 4-12 digits.

@titusz
Copy link
Author

titusz commented Nov 6, 2024

The basic principal is the pin or password should be encrypted or hashed when it is sent to the 'SERVICE'. It is the first step to make sure the leaky. For example, some finance APP will use a special keyboard to input the pin and get an encrypted pin.For trade-off , I propose to hash the pin with UID of the card. BTW, the pin should not be fixed 4 digits, for a client it should be flexible for inputing 4-12 digits.

The PIN is already encrypted when sent to the 'SERVICE' because LNURL requires HTTPS for transport.

Who would hash the pin and why? The card UID can be read by the terminal but it may be a random UID (changing on each read of the card).

@zzzhan
Copy link
Contributor

zzzhan commented Nov 6, 2024

The basic principal is the pin or password should be encrypted or hashed when it is sent to the 'SERVICE'. It is the first step to make sure the leaky. For example, some finance APP will use a special keyboard to input the pin and get an encrypted pin.For trade-off , I propose to hash the pin with UID of the card. BTW, the pin should not be fixed 4 digits, for a client it should be flexible for inputing 4-12 digits.

The PIN is already encrypted when sent to the 'SERVICE' because LNURL requires HTTPS for transport.

Who would hash the pin and why? The card UID can be read by the terminal but it may be a random UID (changing on each read of the card).

Please check our project https://lifpay.me , we will support the feature soon. We know the https is security, but we should not store and verify with the plaintext PIN.

28A5EBBC-D399-4534-97C5-396C2AF33AC6

@zzzhan
Copy link
Contributor

zzzhan commented Nov 15, 2024

Hi Guys,I hope you are doing well! LifPay has implemented this feature. The PIN is compatible from 4~12, hashed before saving to the backend, but verified with the plaintext PIN this moment. @titusz @X-Hades-X

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.