-
-
Notifications
You must be signed in to change notification settings - Fork 10.6k
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
Make tokens URL safe #4490
Make tokens URL safe #4490
Conversation
Base64 encoding causes some issues when the token is URL encoded as the = symbol is not a valid URL character. We replace any = symbols with a - as this is valid in a URL, but is guaranteed not to appear in a base64 string. This fix ensures that Ghost password resets work with mail providers such as Mailgun that add their own tracking redirects closes #3872 (for real this time)
LGTM, although in all fairness and honesty I'd rather we didn't have to do it. However given the circumstances, it seems to be required. The other option is of course to make sure the tldr: lgtm |
Good catch 👍. One question, wouldn't it make more sense to try to decode the URL and deal with
at line 730? |
@sebgie, can the crypto library produce a |
@javorszky no, |
Wait, so the problem is that the email base64 encodes a base64 encoded string? :D But yes, in that case, what @sebgie said. Touch code once instead of twice :). |
It's true that you can just decode on the receiving end, on the off chance that some EDIT: rather than my simple string replace, explicitly calling the built-in encodeURI/decodeURI might be better. |
That sounds like a good plan! |
I've done some more research into this and concluded the following: EncodeURI doesn't work, because it leaves the Further, you can't encode the token using encodeURIComponent, because that produces > encodeURIComponent("fsgfsfASFAsfasdf==")
< "fsgfsfASFAsfasdf%3D%3D"
> encodeURIComponent("fsgfsfASFAsfasdf%3D%3D")
< "fsgfsfASFAsfasdf%253D%253D"
> decodeURIComponent("fsgfsfASFAsfasdf%253D%253D")
< "fsgfsfASFAsfasdf%3D%3D"
/* we wanted == here ^^ */ If the outgoing URI with In other words: the only way to be safe is to ensure you put a valid URI out into the world. In the long term, I have some thoughts about a better way of dealing with reset tokens than the current scheme anyway. In the short term, let's replace |
Thanks for investigating, I'm okay with replacing
Would you mind sharing what you have in mind? |
Sure: We move tokens to their own table. When a reset is requested we generate two tokens, one short used for lookup, one long used for auth. We of course ensure that the lookup token is unique in the token table. Both tokens are generated from URI safe characters, and we put them in the query string, not the path, because that's more idiomatic. The url would look something like: In the database we save, in a
Before storing the token, we prune the table of expired tokens, then get a count of token requests for the submitted email. If there have been too many, we check if any of the tokens are old enough to delete (say, more than 10 minutes old), and check the count again. If it's still too high we deny the request, otherwise we do the token generation and sending. When the user submits the two tokens, we fail if:
Otherwise, all is good and we save the new password. |
@thisishugo thanks for taking the time to write that out! The question on my mind is given the vast amounts of additional complexity - what benefit does this give us? |
Well, there's the rub. It doesn't really add much benefit now.
|
Excellent, this means I didn't miss something important! I agree with all your bullet points, I think that you've specced out an ideal world and it's certainly something to aim for. Because of the required database amends, I think it's something to hold off until we've made that process a bit simpler (plan in progress). Back to this PR - I think that replacing = with - is pretty dirty, but I've read through all your comments several times and I agree that it's the best solution for now. |
Base64 encoding causes some issues when the token is URL encoded
as the = symbol is not a valid URL character. We replace any =
symbols with a - as this is valid in a URL, but is guaranteed
not to appear in a bade64 string. This fix ensures that Ghost
password resets work with mail providers such as Mailgun that
add their own tracking redirects
closes #3872 (for real this time)