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

Don't leak OTP in logs #3123

Merged
merged 9 commits into from
Mar 22, 2023
Merged

Don't leak OTP in logs #3123

merged 9 commits into from
Mar 22, 2023

Conversation

shreyamalviya
Copy link
Contributor

@shreyamalviya shreyamalviya commented Mar 17, 2023

What does this PR do?

Fixes a part of #3077

PR Checklist

  • Have you added an explanation of what your changes do and why you'd like to include them?
  • Is the TravisCI build passing?
  • Was the CHANGELOG.md updated to reflect the changes?
  • Was the documentation framework updated to reflect the changes?
  • Have you checked that you haven't introduced any duplicate code?

Testing Checklist

  • Added relevant unit tests?
  • Do all unit tests pass?
  • Do all end-to-end tests pass?
  • Any other testing performed?

    Added dummy logs and checked that they were correctly formatted

  • If applicable, add screenshots or log transcripts of the feature working

@codecov
Copy link

codecov bot commented Mar 17, 2023

Codecov Report

Patch coverage has no change and project coverage change: -0.01 ⚠️

Comparison is base (fa7e27e) 71.66% compared to head (ccf0aba) 71.65%.

Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #3123      +/-   ##
===========================================
- Coverage    71.66%   71.65%   -0.01%     
===========================================
  Files          449      452       +3     
  Lines        12815    12850      +35     
===========================================
+ Hits          9184     9208      +24     
- Misses        3631     3642      +11     

see 7 files with indirect coverage changes

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report in Codecov by Sentry.
📢 Do you have feedback about the report comment? Let us know in this issue.

Copy link
Collaborator

@mssalvatore mssalvatore left a comment

Choose a reason for hiding this comment

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

Cool idea! My concern, however, is there's no simple way to verify this automatically. Small changes could cause OTPs to leak and we might not notice for quite a while.

I think we can keep this in place for "defense-in-depth" purposes, but I think we need another approach as well.

Maybe commands should only be logged by command builder functions (which can be reused by different exploiters). The command builder function could log the command without the OTP redacted but return the entire command back to the caller.

Another option would be for command builders to return an object whose __str__() method redacts the OTP but you can call a specific method on the object to get back the full command. I kind of like this option. It adds more structure to the command and could be useful in the future.

@VakarisZ
Copy link
Contributor

This solution seems a bit fragile. IF the OTP is logged in an error stack trace (without AGENT_OTP_ENVIRONMENT_VARIABLE_NAME) it will get logged plain text? The best solution I came up on top of my mind is to create a "ISecretVariable" interface. A specific implementation of that interface could use SecretStr. If we store the OTP in this type there's no chance it will get logged.

from common.utils.i_secret_variable import ISecretVariable


class SecretVariable(ISecretVariable):
Copy link
Contributor

@VakarisZ VakarisZ Mar 21, 2023

Choose a reason for hiding this comment

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

Theoretically this should be called something like PydanticSecretVariable, but It's unlikely that we'll need multiple implementations of ISecretVariable, so I kept the name simple

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If it's unlikely that we'll need multiple implementations, why do we have an interface at all?
If we do decide to keep it, I say we rename this to PydanticSecretVariable.

Copy link
Contributor

Choose a reason for hiding this comment

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

It somewhat achieves dependency inversion, which has all kinds of benefits and some drawbacks. The most trivial benefit is for example, that we would be able to create a test MockSecretVariable and pass it wherever ISecretVariable is expected. If there's no interface, we would have to mock the actual SecretVariable. You are right, we don't need the interface ATM, but I think it's better to have it and not need it, than to need it and not have it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fair enough. I think we should rename it then.

@VakarisZ VakarisZ force-pushed the 3077-do-not-leak-otp-in-logs branch from 30ab2fe to 20300c0 Compare March 21, 2023 13:29
Comment on lines 81 to 82
# Custom error message to avoid leaking the OTP
raise IslandAPIAuthenticationError("Failed to retrieve the authentication token")
Copy link
Contributor

Choose a reason for hiding this comment

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

We have no control over what happens in the HTTPClient, but we can suppress the error message

Comment on lines +35 to +37
def format(self, record):
otp_regex = re.compile(f"{AGENT_OTP_ENVIRONMENT_VARIABLE}=[a-zA-Z0-9]*")
otp_replacement = f"{AGENT_OTP_ENVIRONMENT_VARIABLE}={'*' * 6}"
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we still need this? I guess it's unlikely that f"{AGENT_OTP_ENVIRONMENT_VARIABLE}=[a-zA-Z0-9]*" will appear in the logs (because that's not the __repr__ of the OTP)

Copy link
Collaborator

Choose a reason for hiding this comment

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

It provides us with defense-in-depth. Unless it's causing issues, I vote we leave it.

Copy link
Contributor

Choose a reason for hiding this comment

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

That's what I'm saying, it looks like the "depth" we gain is not worth the code we want to add. We are always running against the clock, maintaining the "depth" is not always worth it.

Copy link
Collaborator

@mssalvatore mssalvatore left a comment

Choose a reason for hiding this comment

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

Looks good, but rebase on develop.

@VakarisZ VakarisZ force-pushed the 3077-do-not-leak-otp-in-logs branch from 3a7300a to d7e6869 Compare March 22, 2023 09:17
@VakarisZ VakarisZ force-pushed the 3077-do-not-leak-otp-in-logs branch from 8b0b79c to ccf0aba Compare March 22, 2023 10:20
@VakarisZ VakarisZ merged commit 6fd780d into develop Mar 22, 2023
@VakarisZ VakarisZ deleted the 3077-do-not-leak-otp-in-logs branch March 22, 2023 11:09
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.

None yet

3 participants