4 ms·
Can someone help me understand why the author of the python library chose to raise an exception on verification failures as opposed to returning false?
by worried_citizen 11y ago
Can someone help me understand why the author of the python library chose to raise an exception on verification failures as opposed to returning false?
- mafro 11y agoA core tenet of Python is that "it's easier to ask for forgiveness than permission": https://docs.python.org/2/glossary.html#term-eafp https://docs.python.org/2/glossary.html#term-eafp
- krallin 11y agoThis principle doesn't necessarily mean functions should never return booleans, though. Booleans are used in a variety of (popular) Python libraries when checking whether a password is correct (e.g. Django's `check_password` returns False if the password is wrong).
- lancefisher 11y agoThis is most likely the reason. It allows your code to follow the happy path for logging in, and treat verification as the exceptional case. Definitely a design choice by the author who self-identifies as a Pythonista. def handle_login(): try: ph.verify(hash, "s3kr3tp4ssw0rd") log_login() redirect_to_page() except VerificationError: log_bad_login() redirect_to_login()
- joshmaker 11y agoWhile we're talking Python best practices, I highly recommend using an `else` clause to keep the code being 'excepted' to one line: def handle_login(): try: ph.verify(hash, "s3kr3tp4ssw0rd") except VerificationError: log_bad_login() redirect_to_login() else: log_login() redirect_to_page() It's not a big deal for this code, but in general this is good practice because 1. It makes it very obvious to the next developer which line is the one that is expected to raise that exception 2. One of the other lines could unintentionally raise that exception and mistakenly trigger the except clause. (This is more of an issue with Python's built in exceptions than with something very specific like this `VerificationError` example.)
- hynek 11y agoTwo reasons: 1. mainly: the C library has no concept of “wrong password”; only “verification failed with an error”. If you want to know why it failed, you need the error. As you can see in the example, a wrong password is "Decoding failed” which can also be your fault. It seems like they want to interpret their own failures as little possible. Therefore raising an exception with the error seemed the best way forward. 2. secondarily: in security context, I tend to prefer loud failures for dangerous problems so they don’t pass unnoticed by accident. ymmv
- herge 11y agoOn that topic, if it's raising an exception in the middle of testing the hash, could this permit a timing attack?
- hynek 11y agoIt isn’t raised in the middle of testing the hash. The testing is completely done in the Argon2 C library and the bindings raise an error if it returns an error. The Python library doesn’t do anything smart at all except calling C functions on strings.
- zaroth 11y agoComparisons after hashing are naturally resistant to timing attacks, because you are not in direct control of the bytes being compared. Just ask Bitcoin miners how hard it is to pick an input which results in a hash with a desired n-bit prefix. But as a belt-and-suspenders you often see an attempt at fixed time comparisons of digests in any case. Coincidentally, hashing before comparing can be used in scripting languages where the compare function will often be optimized out from under you, making constant time compare difficult or impossible to actually guarantee.