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).