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

Add JsonWriteFeature.ESCAPE_FORWARD_SLASHES to allow escaping of '/' for String values #507

Closed
cowtowncoder opened this issue Jan 15, 2019 · 12 comments · Fixed by #1197
Closed
Labels
2.17 Issues planned (at earliest) for 2.17

Comments

@cowtowncoder
Copy link
Member

Jackson 2.x only escapes minimum set of characters, as defined by JSON specification. This does not include forward slash character ('/'). But while legal, it turns out that more often than not users do want escaping, to guard against potential inclusion-in-HTML problems, particularly for embedded JSON constants in Javascript sources, in script tags.

Now: although it is possible to enable escaping already (via CharacterEscapes), it is bit verbose, and also adds some measurable (not huge, but not completely trivial) overhead.
So for 3.0 let's add this character as escape-by-default, but also add a simple mechanism for turning that off if feasible (JsonWriteFeature, most likely?).

@MrBuddyCasino
Copy link

MrBuddyCasino commented Sep 15, 2022

I just encountered this difference in a project migrating PHP code to Kotlin. I'm not sure it should be enabled by default, as it makes URLs in Json objects hard to read, but it should be a feature that can easily be enabled. As you have stated, the main reason is to prevent the injection of closing script tags.

Here is an implementation of CharacterEscapes for Java & Kotlin: https://stackoverflow.com/questions/6817520/escape-forward-slash-in-jackson/73770950#73770950

@cowtowncoder
Copy link
Member Author

Right, the setting probably should be disabled by default for Jackson 2.x for backwards-compatibility.
But possibly enabled for 3.0 (master).

But first, it'd need to be implemented; something that is surprisingly bit more complicated than I thought (at least to do it efficiently, and across generator implementations).

@cowtowncoder
Copy link
Member Author

cc @JooHyukKim This is something that would be nice to implement -- basically JsonWriteFeature to force escaping of /, without requiring full CharacterEscapes but also not changing current default behavior.

@JooHyukKim
Copy link
Member

JooHyukKim commented Jan 9, 2024

WDYT of usage like below? @MrBuddyCasino @cowtowncoder

    @Test
    public void testEscapeForwardSlash() throws Exception
    {
        // Given
        Writer jsonWriter = new StringWriter();
        JsonGenerator generator = JsonFactory.builder()
                .enable(JsonWriteFeature.ESCAPE_FORWARD_SLASHES)
                .build()
                .createGenerator(jsonWriter);

        // When
        generator.writeStartObject(); // start object
        generator.writeStringField("url", "http://example.com");
        generator.writeEndObject(); // end object
        generator.close();

        // Then
        assertEquals("{\"url\":\"http:\\/\\/example.com\"}", jsonWriter.toString());
    }

@labkey-matthewb
Copy link

I understand the concern about backward compatibility w/o a major version change. However, the proposal to configure every new instance of ObjectMapper to get the desired behavior is challenging in practice. Because new ObjectMapper() is public it is hard to enforce consistent configuration.

I would propose a way to register a static method to register a Factory for the relevant configuration class. I'm not sure if this should be a Factory of JsonFactory or a lower level configuration class (CharacterEscapes?). This would be a backward compatible mechanism and generally useful beyond the specific issue of escaping the '/' character.

e.g.

JasonFactory registerDefaultJsonFactory(Factory f)

@cowtowncoder
Copy link
Member Author

I am generally against any static, JVM-wide configuration, due to Jackson's usage as an embedded library. This means that trying to force changes for your app/framework/library's needs can easily break other usage.

But there is precedence for doing something like this with StreamReadConstraints / StreamWriteConstraints, wherein ultimate defaults can be changed but can then still be overridden by explicit settings.
This could be considered in this case.

Although TBH, I am not sure I see this as necessarily warranting such change: use case of producing JSON serializations for embedding in HTML is an existing but dominating use case.

Either way, the first step would be to implement JsonWriteFeature, after which possible defaulting could be considered (including implementation technique, something along lines suggested).

@cowtowncoder
Copy link
Member Author

@JooHyukKim yes, exactly, that'd be way to do it. Question is that of how to change encoding tables to add minimal/no overhead.

@cowtowncoder
Copy link
Member Author

Looking at JsonGeneratorImpl subtypes -- WriterBasedJsonGenerator and UTF8JsonGenerator -- the way to go is to figure out how to use alternate output encoding table _outputEscapes. Care needs to be taken as these are shared arrays, but the thing to do is just to make sure index for / (0x2F) forces ecaping; and that's it really.

This would be quite simple if it wasn't for existing setting of custom quote character, for which encoding table is changed.

@JooHyukKim
Copy link
Member

Wrote #1197 draft. Seems oddly straight-forward. Could you PTAL at what I am missing 🤔, @cowtowncoder ?

@cowtowncoder cowtowncoder changed the title Include forward slash ('/') as character to escape by default in String values Add JsonWriteFeature.ESCAPE_FORWARD_SLASHES to allow escaping of '/' for String values Jan 22, 2024
@cowtowncoder cowtowncoder added 2.17 Issues planned (at earliest) for 2.17 and removed 3.x labels Jan 22, 2024
@labkey-matthewb
Copy link

This is great, and cleans up my code quite a bit. So thank you. Is this request considered closed for 3.0? Or is the option of changing the default to include '/' still on the table?

@JooHyukKim
Copy link
Member

So for 3.0 let's add this character as escape-by-default, but also add a simple mechanism for turning that off if feasible (JsonWriteFeature, most likely?).

Seems like original plan was to enable by default (currently disabled in 2.x) @labkey-matthewb.

@cowtowncoder
Copy link
Member Author

I'll create follow-up ticket to change the default for 3.0, and yes agree with @JooHyukKim .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2.17 Issues planned (at earliest) for 2.17
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants