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

Easily mask sensitive headers from request logs by adding HeadersSanitizer #5188

Merged
merged 16 commits into from
Jan 30, 2024

Conversation

seonWKim
Copy link
Contributor

@seonWKim seonWKim commented Sep 16, 2023

Motivation:

Mask sensitive headers when logging request and response headers.

Modifications:

  • Allow users to configure maskHeaders, maskRequestHeaders, maskResponseHeaders when using AbstractFormatterBuilder implementations. (e.g. TextLogFormatterBuilder, JsonLogFormatterBuilder)
  • Use values from maskRequestHeaders and maskResponseHeaders to mask request and response headers

Result:

Users are able to easily mask request and response headers:

HeadersSanitizer
  .builderForText()
  .sensitiveHeaders("Authorization"...)
  .maskingFunction((name, value) -> "....")
  .build()

@codecov
Copy link

codecov bot commented Sep 16, 2023

Codecov Report

Attention: 5 lines in your changes are missing coverage. Please review.

Comparison is base (9568d56) 0.00% compared to head (a837197) 74.01%.
Report is 137 commits behind head on main.

Files Patch % Lines
...ia/common/logging/JsonHeadersSanitizerBuilder.java 66.66% 2 Missing and 1 partial ⚠️
...p/armeria/common/logging/TextHeadersSanitizer.java 94.11% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##             main    #5188       +/-   ##
===========================================
+ Coverage        0   74.01%   +74.01%     
- Complexity      0    20744    +20744     
===========================================
  Files           0     1799     +1799     
  Lines           0    76422    +76422     
  Branches        0     9728     +9728     
===========================================
+ Hits            0    56561    +56561     
- Misses          0    15258    +15258     
- Partials        0     4603     +4603     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@jrhee17 jrhee17 added this to the 1.26.0 milestone Sep 18, 2023
Copy link
Contributor

@jrhee17 jrhee17 left a comment

Choose a reason for hiding this comment

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

Left a preliminary comment 🙇

@seonWKim seonWKim force-pushed the mask-sensible-headers branch from 76e2dcc to 6e5df41 Compare October 4, 2023 16:38
@seonWKim seonWKim changed the title Add maskHeaders, maskRequestHeaders, maskResponseHeaders for LogFormatter Easily mask sensitive headers from request logs by adding HeadersSanitizer Oct 5, 2023
@minwoox minwoox modified the milestones: 1.26.0, 1.27.0 Oct 11, 2023
@seonWKim
Copy link
Contributor Author

seonWKim commented Dec 1, 2023

Sorry for the late reply. I will work on the issue again 🙇

@ikhoon
Copy link
Contributor

ikhoon commented Dec 4, 2023

The Git history looks messed up. Changes of +14,386 −3,985 are not made by in this PR.
Could you clean the Git history of this PR with squash, reset, etc?

@seonWKim seonWKim force-pushed the mask-sensible-headers branch from e690150 to e8ee73d Compare December 4, 2023 23:38
@seonWKim seonWKim closed this Dec 4, 2023
@seonWKim seonWKim reopened this Dec 4, 2023
@seonWKim seonWKim force-pushed the mask-sensible-headers branch from e8ee73d to 3c163cb Compare December 6, 2023 14:45
- fix comments
- change method order
/**
* Sets the {@link Set} which includes headers to mask before logging.
*/
public AbstractHeadersSanitizerBuilder<T> maskHeaders(String... headers) {
Copy link
Contributor

Choose a reason for hiding this comment

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

  • The headers defined in HttpHeaderNames should be compatible without additional casting.
  • maskingHeaders or sensitiveHeaders is preferred over maskHeaders because this function sets the headers to be masked, not the actual action.
Suggested change
public AbstractHeadersSanitizerBuilder<T> maskHeaders(String... headers) {
public AbstractHeadersSanitizerBuilder<T> maskingHeaders(CharSequence... headers) {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great point. I'll apply as below

  • maskHeaders -> maskingHeaders
  • mask -> maskingFunction

@seonWKim
Copy link
Contributor Author

seonWKim commented Jan 6, 2024

@ikhoon , should the masking function be case insensitive? For example, if user set maskingHeaders("set-cookie"), should we mask "Set-Cookie" header(which is uppercase)?

- Fix naming
- Mask sensitive headers by default
@seonWKim seonWKim force-pushed the mask-sensible-headers branch from f35a31e to 0904f65 Compare January 7, 2024 01:47
@ikhoon
Copy link
Contributor

ikhoon commented Jan 18, 2024

HTTP header names are case-insensitive as per https://www.rfc-editor.org/rfc/rfc2616#section-4.2

@minwoox
Copy link
Contributor

minwoox commented Jan 24, 2024

I pushed changes that fix some style issued. PTAL. 😉

@seonWKim
Copy link
Contributor Author

seonWKim commented Jan 24, 2024

I pushed changes that fix some style issued. PTAL. 😉

@minwoox Thanks for cleaning up the mess I've made 🙇 . The PR seems ready 👍

Copy link
Contributor

@jrhee17 jrhee17 left a comment

Choose a reason for hiding this comment

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

Looks nice! Thanks @seonwoo960000 🙇 👍 🙇

@ikhoon ikhoon requested a review from jrhee17 January 29, 2024 10:22
@ikhoon
Copy link
Contributor

ikhoon commented Jan 29, 2024

@jrhee17 Sorry, I've made some changes after your review. PTAL tomorrow. 🙇‍♂️

Copy link
Contributor

@minwoox minwoox left a comment

Choose a reason for hiding this comment

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

Still, looks good to me. Thanks! 😉

- A header name is necessary to dynamically mask header values.
- Handle a null value returned by masking functions.
- Replace Function<String,String` with `HeaderMaskingFunction`.
- `HeaderSanitizer` their builders are moved to `common.logging` from
  `common`.
Copy link
Contributor

@jrhee17 jrhee17 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! Thanks @ikhoon 🙇 👍 🙇

Copy link
Contributor

@ikhoon ikhoon left a comment

Choose a reason for hiding this comment

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

Nice work! Thanks, @seonwoo960000 🙇‍♂️🚀

@ikhoon ikhoon merged commit 2400845 into line:main Jan 30, 2024
16 of 17 checks passed
ikhoon added a commit to ikhoon/armeria that referenced this pull request Mar 19, 2024
Motivation:

`HeadersSanitizer` was added in line#5188. If no `HeadersSanitizer` is set,
the default santizer masks `Authorization`, `Cookie` `Set-Cookie` and
`Proxy-Authorization` with `****`.

In addition to `HeadersSantizer`, other new features are added to
`LoggingDecoratorBuilder` and the code became messy to maintain
backward compatibility. `LoggingDecoratorBuilder`, `LogWriterBuilder`,
and `LogFormatterBuilder` each have their own properties, so it was not
easy to make the overall operation consistent.

As a result, while `LoggingClient.newDecorator()` santizes sensitive
headers, LoggingClient.builder().requestLogLevel(...).newDecorator()`
did not work. Neither code set a sanitizer, so a default sanitizer
should have been set, but it didn't.

Modifications:

- Refactor `LoggingDecoratorBuilder` to delegate all builder properties
  to either `LogWriterBuilder` or `LogFormatterBuilder`.
- Add missing `@Deprecated` annotation to `LoggingClientBuilder` and
  `LoggingRpcClientBuilder` and `LoggingServiceBuilder`.
  - `@Deprecated` in the super method aren't inspected by IntelliJ line#5395
- Breaking) Change the signature of `LogWriterBuilder.responseCauseFilter()`
  to have `RequestContext` as the first parameter.
  - It may be a bug or a mistake when adding the API. Our APIs
    usually provide `RequestContext` for predicates or handlers.

Result:

`LoggingClient` and `LoggingService` now correctly mask sensitive
headers by default.
jrhee17 pushed a commit that referenced this pull request Apr 2, 2024
…ng decorators (#5519)

Motivation:

`HeadersSanitizer` was added in #5188. If no `HeadersSanitizer` is set,
the default sanitizer masks `Authorization`, `Cookie` `Set-Cookie`, and
`Proxy-Authorization` with `****`.

In addition to `HeadersSantizer`, other new features were added to
`LoggingDecoratorBuilder` and the code became messy to maintain backward
compatibility. `LoggingDecoratorBuilder`, `LogWriterBuilder`, and
`LogFormatterBuilder` each have their own properties, so making the
overall operation consistent was not easy.

As a result, while `LoggingClient.newDecorator()` sanitizes sensitive
headers, LoggingClient.builder().requestLogLevel(...).newDecorator()`
did not work. Neither code set a sanitizer, so a default sanitizer
should have been set, but it didn't.

Modifications:

- Refactor `LoggingDecoratorBuilder` to delegate all builder properties
to either `LogWriterBuilder` or `LogFormatterBuilder`.
- Add missing `@Deprecated` annotation to `LoggingClientBuilder` and
`LoggingRpcClientBuilder` and `LoggingServiceBuilder`.
  - `@Deprecated` in the super method isn't inspected by IntelliJ #5395
- Breaking) Change the signature of
`LogWriterBuilder.responseCauseFilter()` to have `RequestContext` as the
first parameter.
- It may be a bug or a mistake when adding the API. Our APIs usually
provide `RequestContext` for predicates or handlers.

Result:

`LoggingClient` and `LoggingService` now correctly mask sensitive
headers by default.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Easily mask sensitive headers from request logs
5 participants