Skip to content

Enable debug_redact for Java Logging #13576

Open
@anilburakbilsel

Description

What language does this apply to?

Java and Proto version -> libprotoc 23.4

Describe the problem you are trying to solve.

There are many ways that protocol buffers might be stringified into logs and then printed into stack traces or service/application logs, etc. The built-in behavior stringifies the entire protocol buffer (protobuf) recursively, including all field data.

So for example, assuming that Person is a protobuf generated class (so it extends com.google.protobuf.GeneratedMessageV3) and there is an instance of it "person" then System.out.print(person); will print all the fields and values.

I can see a two conversations going on around redacting sensitive information from protocol buffers when they are stringified. Those discussions can be found at:

It seems like debug_redact has been added into descriptor.proto and generate the code, I can see that the generated Java files can have access to it. However, when I try to stringfy the object, the values for debug_redactenabled fields are still being printed into the logs. I believe that happens because there is no check in toString() method for this field in Java.

Describe the solution you'd like

It seems like currently toString() method uses private printFieldValue() method while stringifyinh values - and it does not check whether the descriptor is being used or not - or whether debug_redact set to true or not. Maybe we can add a check at the beginning of that method, so that if the debug_redact is set to true then the value will not be printed. The following might be added before line 546 (in this method), where the switch statement is:

......
    private void printFieldValue(
        final FieldDescriptor field, final Object value, final TextGenerator generator)
        throws IOException {
      if (field.getOptions().hasDebugRedact() && field.getOptions().getDebugRedact()) {
        break;  // do not print anything
     }
      switch (field.getType()) {
        case INT32:
        case SINT32:
        case SFIXED32:
......
}

There are other ways to achieve this goal as well but this is a straigtforward solution I believe.

Dear @acozzette, I kindly wanted to ping you as well since you have some background information and idea about this issues. And it seems like you also recently made some changes into TextFormat.java class.

Additional context

private void printFieldValue(
final FieldDescriptor field, final Object value, final TextGenerator generator)
throws IOException {
switch (field.getType()) {
case INT32:
case SINT32:
case SFIXED32:
generator.print(((Integer) value).toString());
break;
case INT64:
case SINT64:
case SFIXED64:
generator.print(((Long) value).toString());
break;
case BOOL:
generator.print(((Boolean) value).toString());
break;
case FLOAT:
generator.print(((Float) value).toString());
break;
case DOUBLE:
generator.print(((Double) value).toString());
break;
case UINT32:
case FIXED32:
generator.print(unsignedToString((Integer) value));
break;
case UINT64:
case FIXED64:
generator.print(unsignedToString((Long) value));
break;
case STRING:
generator.print("\"");
generator.print(
escapeNonAscii
? TextFormatEscaper.escapeText((String) value)
: escapeDoubleQuotesAndBackslashes((String) value).replace("\n", "\\n"));
generator.print("\"");
break;
case BYTES:
generator.print("\"");
if (value instanceof ByteString) {
generator.print(escapeBytes((ByteString) value));
} else {
generator.print(escapeBytes((byte[]) value));
}
generator.print("\"");
break;
case ENUM:
generator.print(((EnumValueDescriptor) value).getName());
break;
case MESSAGE:
case GROUP:
print((MessageOrBuilder) value, generator);
break;

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions