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

Mask Authorization header when showing RequestError #1125

Closed
nkottary opened this issue Nov 20, 2023 · 2 comments
Closed

Mask Authorization header when showing RequestError #1125

nkottary opened this issue Nov 20, 2023 · 2 comments

Comments

@nkottary
Copy link
Contributor

  • Julia 1.9.3
  • HTTP.jl 1.10.0
  • MbedTLS.jl 1.1.7

The problem: The value of the Authorization header is printed as is when displaying a RequestError. This leaks the token in the key to the logs.

Steps to reproduce:

  1. The following HTTP server has an error in it, so it will result in an eof error for clients:
using HTTP

# start a blocking server
HTTP.listen() do http::HTTP.Stream
    @show http.message
    @show HTTP.header(http, "Content-Type")
    while !eof(http)
        println("body data: ", String(readavailable(http)))
    end
    HTTP.setstatus(http, 404)
    HTTP.setheader(http, "Foo-Header" => "bar")
    HTTP.startwrite(http)
    HTTP.close!(http)    # Error
    return
    write(http, "response body")
    write(http, "more response body")
end

Run this as a server: julia server.jl

  1. Send a request to this server with an Authorization header:
using HTTP
using JSON

function run_get()
    headers = [
        "Content-Type" => "application/json",
        "Authorization" => "Basic LeakedOhNo",
        "Accept" => "*/*",
    ]

    body = JSON.json(
        Dict(
            "values" => ["a", "b"]
        )
    )
    resp = HTTP.post(
        "http://localhost:8081/";
        headers=headers,
        body=body,
    )
end

Example:

$ julia
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.9.3 (2023-08-24)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

julia> include("client.jl")
run_get (generic function with 1 method)

julia> run_get()
  1. This results in error with Authorization header revealed in stacktrace:
ERROR: HTTP.RequestError:
HTTP.Request:
HTTP.Messages.Request:
"""
POST / HTTP/1.1
Content-Type: application/json
Authorization: Basic LeakedOhNo
Accept: */*
Host: localhost:8081
User-Agent: HTTP.jl/1.9.3
Content-Length: 20
Accept-Encoding: gzip

{"values":["a","b"]}"""Underlying error:
EOFError: read end of file
Stacktrace:
  [1] (::HTTP.ConnectionRequest.var"#connections#4"{HTTP.ConnectionRequest.var"#connections#1#5"{HTTP.TimeoutRequest.var"#timeouts#3"{HTTP.TimeoutRequest.var"#timeouts#1#4"{HTTP.ExceptionRequest.var"#exceptions#2"{HTTP.ExceptionRequest.var"#exceptions#1#3"{typeof(HTTP.StreamRequest.streamlayer)}}}}}})(req::HTTP.Messages.Request; proxy::Nothing, socket_type::Type, socket_type_tls::Type, readtimeout::Int64, connect_timeout::Int64, logerrors::Bool, logtag::Nothing, kw::Base.Pairs{Symbol, Union{Nothing, Int64}, Tuple{Symbol, Symbol, Symbol}, NamedTuple{(:iofunction, :decompress, :verbose), Tuple{Nothing, Nothing, Int64}}})
    @ HTTP.ConnectionRequest ~/.julia/packages/HTTP/SN7VW/src/clientlayers/ConnectionRequest.jl:143
  [2] (::Base.var"#90#92"{Base.var"#90#91#93"{ExponentialBackOff, HTTP.RetryRequest.var"#2#5"{Int64, typeof(HTTP.RetryRequest.FALSE), HTTP.Messages.Request, Base.RefValue{Int64}}, HTTP.ConnectionRequest.var"#connections#4"{HTTP.ConnectionRequest.var"#connections#1#5"{HTTP.TimeoutRequest.var"#timeouts#3"{HTTP.TimeoutRequest.var"#timeouts#1#4"{HTTP.ExceptionRequest.var"#exceptions#2"{HTTP.ExceptionRequest.var"#exceptions#1#3"{typeof(HTTP.StreamRequest.streamlayer)}}}}}}}})(args::HTTP.Messages.Request; kwargs::Base.Pairs{Symbol, Union{Nothing, Int64}, Tuple{Symbol, Symbol, Symbol}, NamedTuple{(:iofunction, :decompress, :verbose), Tuple{Nothing, Nothing, Int64}}})
    @ Base ./error.jl:296
@fredrikekre
Copy link
Member

IIUC this isn't really a leak since it just prints the request which resulted in the error. Still a good idea to skip printing of sensitive headers I suppose.

nkottary added a commit to nkottary/HTTP.jl that referenced this issue Nov 23, 2023
Edits the `show` and `writeheaders` methods to hide the value of Authorization header.
This hides the Authorization header when `Request` or `RequestError` objects are `show`n.

Fix for JuliaWeb#1125
nkottary added a commit to nkottary/HTTP.jl that referenced this issue Nov 27, 2023
Edits the `show` and `writeheaders` methods to hide the value of Authorization header.
This hides the Authorization header when `Request` or `RequestError` objects are `show`n.

Fix for JuliaWeb#1125
fredrikekre pushed a commit to nkottary/HTTP.jl that referenced this issue Nov 28, 2023
Edits the `show` and `writeheaders` methods to hide the value of Authorization header.
This hides the Authorization header when `Request` or `RequestError` objects are `show`n.

Fix for JuliaWeb#1125
@fredrikekre
Copy link
Member

Fixed by #1126 (and #1127 should mitigate any similar possible leaks).

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

No branches or pull requests

2 participants