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

fix: redact passwords in logs #1219

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

martinohmann
Copy link

Fixes #238

Replaces URLs of the format rtsp://user:password@localhost:8554 with rtsp://user:xxxxx@localhost:8554 in logs.

This is best-effort for now and does not handle cases where passwords appear in query strings. It should be fairly easy to extend the RedactPassword function in the future in case there are other common password pattern that are worth handling.

Let me know if this should be better placed in a different package. I couldn't find a more suitable place than streams and also didn't want to introduce a new package like utils just for a single function.

Fixes AlexxIT#238

Replaces URLs of the format `rtsp://user:password@localhost:8554` with
`rtsp://user:xxxxx@localhost:8554` in logs. This is best-effort for now
and does not handle cases where passwords appear in query strings. It
should be fairly easy to extend the `RedactPassword` function in the
future in case there are other common password pattern that are worth
handling.
@@ -20,3 +20,11 @@ func ParseQuery(s string) url.Values {
}
return params
}

func RedactPassword(s string) string {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Theoretically, this could be private since it's only used in this module so far.

@AlexxIT AlexxIT self-assigned this Jun 21, 2024
@AlexxIT
Copy link
Owner

AlexxIT commented Jun 21, 2024

I thought about this feature. Problem not only with logs, but also with another places.
URLs not always just urls, but also ffmpeg and exec sources with url.
Also we have REST API for streams (json) and for graph (dot) and for logs and for config!

@martinohmann
Copy link
Author

martinohmann commented Jun 21, 2024

Yeah, some places might be tricky. Redacting passwords for the /api/streams.dot endpoint should be easy and I can add that here as well if you like.

However, we cannot really redact them from the /api/streams endpoint as it would make it impossible to consume these streams then. Also, it's not possible for /api/config because of the edit functionality we have in the UI and redacting passwords there would break the config on save. These would require API auth to properly secure them which is already supported.

For me it would be already helpful if these passwords do not end up in the logs. Having them exposed via the API is less of a concern for me because I restrict access to this to trusted services only (home assistant in my case).

@martinohmann
Copy link
Author

FWIW, I found these examples from the README, that I could probably also redact here:

streams:
  # Custom header
  custom_header: "https://mjpeg.sanford.io/count.mjpeg#header=Authorization: Bearer XXX"
streams:
  # OAuth credentials
  nest-doorbell: nest:?client_id=***&client_secret=***&refresh_token=***&project_id=***&device_id=***
streams:
  # link to external Hass with Long-Lived Access Tokens
  hass-webrtc2: hass://192.168.1.123:8123?entity_id=camera.nest_doorbell&token=eyXYZ...

I'll have a look how to handle sources like ffmpeg and nest in the redact logic. My current impl only works for URLs without an explict source.

@AlexxIT
Copy link
Owner

AlexxIT commented Jun 21, 2024

streams.dot it's just reformat streams.json. Not necessary to fix it separately.

@martinohmann
Copy link
Author

martinohmann commented Jun 25, 2024

@AlexxIT I pushed a new commit which expands the logic to also redact sensitive values in query parameters, # stream options and URLs within exec sources. It also is aware of redirects now. You can have a look at the added test cases to see what's supported now.

Let me know what you think.

This also deals with query parameters, stream options and is aware of
potentially existing redirects.
@skrashevich
Copy link
Contributor

Maybe, it be useful to detect passwords in string by entropy calculation?

func entropy(text string) float64 {
	textLength := len(text)
	if textLength == 0 {
		return 0.0
	}

	uniqueCharacters := make(map[rune]int, textLength)
	for _, r := range text {
		uniqueCharacters[r]++
	}

	var entropy float64
	textLengthFloat := float64(textLength)
	log2 := math.Log(2)
	for _, count := range uniqueCharacters {
		probability := float64(count) / textLengthFloat
		entropy -= probability * (math.Log(probability) / log2)
	}

	return entropy
}

@martinohmann
Copy link
Author

martinohmann commented Jun 28, 2024

@skrashevich Nice idea, but still this wouldn't catch cases where people use low-entropy passwords.

@AlexxIT If you're not satisfied with the solution in this PR there's also another simpler alternative to this problem. Right now, the main issue is that stream urls (which potentially contain passwords) end up in the logs at Info level, which is the default. We could change these log statements to Debug/Trace instead to have them not show up in the logs by default.

That would solve the issue for me at least. Within certain modules we could probably switch from logging the stream url to logging the stream name instead (at Info level) to not lose too much information.

I can provide a PR to update the log levels if that sounds reasonable for you.

I'm personally also not 100% happy with this PR here as it's adding quite a bit of code for a minor thing that does not really contribute to the core logic to go2rtc.

@AlexxIT
Copy link
Owner

AlexxIT commented Jun 29, 2024

Just haven't time to check it yet

martinohmann added a commit to martinohmann/go2rtc that referenced this pull request Sep 6, 2024
This solves the most prominent credential leak. With every new
connection the passwords were leaked to the logs visible in the UI as
well.

With this change only the stream name gets logged here.

There are other places in the codebase where we still log secret
embedded in URLs, but a lot of them lack access to the stream name they
could be replaced with. Most of these occurances are debug logs, but
some are warning level though. I can try to come up with a fix in a
followup PR.

This change is a simpler alternative to
AlexxIT#1219 to address the issue to rid
of the password in the log line emitted whenever a stream is created:

    [streams] create new stream url=rtsp://stream:[email protected]:554/stream1

    [streams] create new stream garage-cam
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

Successfully merging this pull request may close these issues.

Mask passwords in logs
3 participants