diff --git a/CHANGELOG.md b/CHANGELOG.md index 381bca667..075987845 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Server errors are no longer serialized back to the client since this might leak sensitive information through the error message. ([#1126]) +- When `show`ing `HTTP.Request` and `HTTP.Response` the values for the headers + `Authorization`, `Proxy-Authorization`, `Cookie`, and `Set-Cookie` are masked with `*`s + since they might include sensitive information. ([#1127]) ### Fixed - Restrict `HTTP.isredirect` to arguments of integer types. ([#1117]) - Fix `HTTP.getcookies` error when key doesn't exist. ([#1119]) diff --git a/src/Messages.jl b/src/Messages.jl index bc61d10e9..88ad23409 100644 --- a/src/Messages.jl +++ b/src/Messages.jl @@ -609,7 +609,16 @@ function Base.show(io::IO, m::Message) end println(io, typeof(m), ":") println(io, "\"\"\"") - writeheaders(io, m) + + # Mask the following (potentially) sensitive headers with "******": + # - Authorization + # - Proxy-Authorization + # - Cookie + # - Set-Cookie + header_str = sprint(writeheaders, m) + header_str = replace(header_str, r"(*CRLF)^((?>(?>Proxy-)?Authorization|(?>Set-)?Cookie): ).+$"mi => s"\1******") + write(io, header_str) + summary = bodysummary(m.body) validsummary = isvalidstr(summary) validsummary && write(io, summary) diff --git a/test/messages.jl b/test/messages.jl index fbad5e893..29c39fc3f 100644 --- a/test/messages.jl +++ b/test/messages.jl @@ -197,6 +197,20 @@ using JSON # https://github.com/JuliaWeb/HTTP.jl/issues/828 # don't include empty headers in request when writing @test repr(Request("GET", "/", ["Accept" => ""])) == "Request:\n\"\"\"\nGET / HTTP/1.1\r\n\r\n\"\"\"" + + # Test that sensitive header values are masked when `show`ing HTTP.Request and HTTP.Response + for H in ["Authorization", "Proxy-Authorization", "Cookie", "Set-Cookie"], h in (lowercase(H), H) + req = HTTP.Request("GET", "https://xyz.com", [h => "secret", "User-Agent" => "HTTP.jl"]) + req_str = sprint(show, req) + @test !occursin("secret", req_str) + @test occursin("$h: ******", req_str) + @test occursin("HTTP.jl", req_str) + resp = HTTP.Response(200, [h => "secret", "Server" => "HTTP.jl"]) + resp_str = sprint(show, resp) + @test !occursin("secret", resp_str) + @test occursin("$h: ******", req_str) + @test occursin("HTTP.jl", resp_str) + end end @testset "queryparams" begin