benoitc / hackney

simple HTTP client in Erlang
Other
1.34k stars 427 forks source link

Basic Auth credentials passed via URL are not URL-decoded before encoding to Base64 #595

Closed dvgica closed 4 years ago

dvgica commented 4 years ago

Hello,

Hackney allows you to pass basic auth credentials via a URL like this: http://Aladdin:open@example.com. These credentials are properly translated into a basic auth header like Authorization: Basic QWxhZGRpbjpvcGVu, which is sent with the request.

However, when a URL-encoded username or password is given, the resulting Authorization header is incorrect, because the username and password are not URL-decoded by Hackney before they are base64 encoded for the Authorization header. For example, the URL http://Aladdin:open%20sesame@example.com results in the following header: Authorization: Basic QWxhZGRpbjpvcGVuJTIwc2VzYW1l. When you base64 decode that header, you get Aladdin:open%20sesame.

This exact example is used in the HTTP Basic Auth RFC, where it shows that the correct header is actually Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==.

I suspect this bug is present because hackney_url does not URL-decode the user/pass, but I'm not sure if this is the right place to fix it:

iex(24)> :hackney_url.parse_url("https://Aladdin:open%20sesame@example.com")                         
{:hackney_url, :hackney_ssl, :https, "example.com", "", "/", "", "",
 'example.com', 443, "Aladdin", "open%20sesame"}

Until this is fixed, my workaround is to manually extract the user/pass from the URL before passing it to Hackney, URL-decoding myself, and passing the decoded user/pass via the basic_auth options.