I have an app that uses Express mongoose as its backend, and React as its frontend. On the backend, the validation of user input is done by express-validator the following way:
body('text')
.trim()
.escape()
.not()
.isEmpty()
.withMessage('Comment should contain something, right?'),
The mongoose model schema:
const commentSchema = new Schema<IComment>({
author: String,
post: {
type: SchemaTypes.ObjectId,
ref: 'Post',
},
text: {
type: String,
},
date: Date,
});
The text and author properties are what I have trouble with. I made sure the data comes to the backend unescaped, and from the backend it comes escaped (and only once, by express-validator). However, when I try to render in React a string coming from the backend like that's the (it contains ' character), it's rendered in the browser as that's the. When I inspected the element, I found that the ampersand has been replaced with &, and the string ended up being displayed exactly the way it came from the backend. It appears that the ampersand was doubly escaped. Is there a way to prevent this without installing any external libraries and using dangerouslySetInnerHTML? I just don't want this ampersand to be escaped. My assumption is that it's done by React.
The component has the following structure:
<Wrapper>
<Author>{author}</Author>
<Text>{text}</Text>
<Date>{date}</Date>
</Wrapper>
Same happens if I insert all the values in a plain <div>.
EDIT: If I hardcode something like <html> right into the JSX tag, everything works fine. If I hardcode {"<html>"}, this is treated as a string and is escaped. The data coming from the backend is, well, string, but already escaped.
CodePudding user response:
Just send plain unescaped strings from back-end.
It should be front-end who decides how to render and whether to escape the data, and unless you use dangerouslySetInnerHTML you are safe.
Let's say somebody has written a comment containing xss script. You can save the comment in a database as is, and then React will automatically escape it for you, so that script will never be evaluated (again, unless you use dangerouslySetInnerHTML to render the comment).
