您已经了解了如何验证从外部世界进入 Express 应用程序的输入。

当您运行面向公众的服务器时,您会很快明白一件事:永远不要相信输入。

即使您使用客户端代码对输入进行了消毒和确保人们无法输入奇怪的东西,您仍然可能受到人们使用工具(甚至仅仅是浏览器开发工具)直接POST到您的端点的影响。

或者机器人尝试使用人类已知的每种攻击方式的组合。

您需要做的是对输入进行消毒。

您已经使用的express-validator 也可以方便地用于执行消毒操作。

假设您有一个POST端点接受name、email和age参数:

const express = require('express')
const app = express()

app.use(express.json())

app.post('/form', (req, res) => {
 const name = req.body.name
 const email = req.body.email
 const age = req.body.age
})

您可以使用以下方式进行验证:

const express = require('express')
const app = express()

app.use(express.json())

app.post('/form', [
 check('name').isLength({ min: 3 }),
 check('email').isEmail(),
 check('age').isNumeric()
], (req, res) => {
 const name = req.body.name
 const email = req.body.email
 const age = req.body.age
})

您可以通过在验证方法之后添加消毒方法来添加消毒操作:

app.post('/form', [
 check('name').isLength({ min: 3 }).trim().escape(),
 check('email').isEmail().normalizeEmail(),
 check('age').isNumeric().trim().escape()
], (req, res) => {
 //...
})

在这里,我使用了以下方法:

  • trim() 去除字符串开头和结尾的字符(默认为空格)
  • escape() 用相应的 HTML 实体替换 <, >, &, ', "/
  • normalizeEmail() 统一 email 地址的格式。可以接受多个选项,比如将 email 地址转换为小写或去掉子邮箱(例如 [[email protected]](/cdn-cgi/l/email-protection)

其他的消毒方法:

  • blacklist() 移除黑名单中出现的字符
  • whitelist() 移除不在白名单中的字符
  • unescape() 将 HTML 编码的实体替换为 <, >, &, ', "/
  • ltrim() 类似于 trim(),但只会去除字符串开头的字符
  • rtrim() 类似于 trim(),但只会去除字符串结尾的字符
  • stripLow() 移除 ASCII 控制字符,这些字符通常是不可见的

强制将输入转换为特定格式:

  • toBoolean() 将输入字符串转换为布尔值。除了 ‘0’、‘false’ 和 ’’ 之外,一切都会返回 true。在严格模式下,只有 ‘1’ 和 ’true’ 返回 true
  • toDate() 将输入字符串转换为日期,如果输入不是日期则返回 null
  • toFloat() 将输入字符串转换为浮点数,如果输入不是浮点数则返回 NaN
  • toInt() 将输入字符串转换为整数,如果输入不是整数则返回 NaN

与自定义验证器类似,您也可以创建自定义的消毒器。

在回调函数中,您只需返回经过消毒处理的值:

const sanitizeValue = value => {
 // 消毒处理...
}

app.post('/form', [
 check('value').customSanitizer(value => {
 return sanitizeValue(value)
 }),
], (req, res) => {
 const value = req.body.value
})