0

Say that I am getting text from a database that includes #hashtags. I want to add this text to the inner content of a <Post> element. However, I would like to process this text so that the hashtags are wrapped in an <a/> element, so it is not as simple as just including all the plaintext content as a child of Post like <Post>my text here</Post>.

Currently what I am doing is:

function Post(props: Post) {
  // ...
  return(
    <div>
      {textPreprocessor(props.text)}
    </div>
)}

//...

const textPreprocessor = (content : string) : React.ReactNode => {
    // adds hashtags
    let words = content.split(" ");
    let htmlString = ""
    words.forEach(word  => {
        if(word[0] === "#") {
            htmlString += `<a href='hashtag/:${word}'/>${word}</a> `
        }
        else{
            htmlString += `${word} `
        }
    })
    
    return <div dangerouslySetInnerHTML={{__html: htmlString}} />;
}

Now this "works", but it's also extremely dangerous. People can just write whatever HTML/JS they want into the database and it will be executed in the frontend. Is there a safer way to do this?

2 Answers 2

1

There are some libraries for that, like dompurify. Those libraries add some more security for this, but you should always consider this to be dangerous and try to avoid such things.

Sign up to request clarification or add additional context in comments.

2 Comments

despite it being dangerous, I assume it's a relatively common practice given how pervasive inline #hashtags and @ mentions are... I wonder if there's a better way than setting innerHTML? Regardless, thanks for the library suggestion. I think the main change I will make is sanitizing my string as the first step of textPreprocessor before adding the custom html elements
I think that sanitizing string and maybe some validation might be enough. You might want to provide some secure way of adding those hashtags, for example when user try to add some hashtag, you check if there are only allowed characters in it, and if it is a mention, you can check if user exist and can be mentioned before saving that mention
0

A preliminary safer solution based off @Oleg's answer, which does not use any 3rd party libraries, is that I created a new function:

const sanitizeHTML = (unsanitized : string) : string => {
    const el : HTMLDivElement = document.createElement("div");
    el.innerText = unsanitized;
    return el.innerHTML;
}

and then made a slight modification to textPreprocessor

const textPreprocessor = (content : string) : React.ReactNode => {
    // adds hashtags
    const sanitized = sanitizeHTML(content)
    const words = content.split(" ");
    let htmlString = ""
    words.forEach(word  => {
        if(word[0] === "#") {
            htmlString += `<a href='hashtag/:${word}'/>${word}</a> `
        }
        else{
            htmlString += `${word} `
        }
    })
    
    return <div dangerouslySetInnerHTML={{__html: htmlString}} />;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.