我有一个带有onSubmit函数的表单从状态收集输入数据并将其发送到后端. 然后我收集来自req.body的输入和来自后端头部的ip. ip被持久化为redis,表单输入通过pm2传递给另一个守护进程,最后用
然后我收集来自req.body的输入和来自后端头部的ip.
ip被持久化为redis,表单输入通过pm2传递给另一个守护进程,最后用mandrill邮寄,而不是持久保存到任何数据库.
情景一
收集客户端IP并将其保留为redis:
module.exports = (req, res, next) => {
const client = redis.createClient()
client.select(2, (err) => {
console.log('redisWriteIP selected 2snd redis db')
if (err) {
next(new DbErr(err))
} else {
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress
client.set(ip, true, 'EX', 120, (err, rep) => {
if (err) {
next(new DbErr(err))
} else {
return next()
}
})
}
})
}
问题1:
在这种情况下,我是否需要清理ip?用户可以使用请求标头发脾气并发送除了他的IP地址或号码之外的任何其他内容吗?
情景2
输入字段由用户填写并发送到req.body上的api
api服务器 – 使用body解析器:
const api = express()
// Body parser for the post requests
const bodyParser = require('body-parser')
api.use(bodyParser.urlencoded({ extended: false }))
api.use(bodyParser.json())
api.set('trust proxy', 'loopback')
const routes = require('./routes')
api.use('/api', routes)
验证字段middlware:
module.exports = (req, res, next) => {
let payload = req.body
const err = {}
let isFormValid = true
// Validating a form.
if (payload.question) {
if (typeof payload.email !== 'string' || !validator.isEmail(payload.email)) {
isFormValid = false
err.email = 'Please provide a correct email address.'
}
if (typeof payload.name !== 'string' || payload.name.trim().length === 0) {
isFormValid = false
err.name = 'Please provide your name.'
}
// Validating another form.
} else if (payload.booking) {
if (typeof payload.email !== 'string' || !validator.isEmail(payload.email)) {
isFormValid = false
err.email = 'Please provide a correct email address.'
}
if (typeof payload.dates !== 'string' || payload.dates.trim().length === 0) {
isFormValid = false
err.msg = 'Something went wrong'
}
} else {
// No form type in the payload.
isFormValid = false
err.msg = 'Something went wrong'
}
if (!isFormValid) {
next(new FormFieldErr(JSON.stringify(err)))
} else {
return next()
}
}
数据如何发送到另一个进程的示例:
...
// Send the payload to the mandrill pid.
pm2.sendDataToProcessId(pid, payload, (err, res) => {
if (err) {
next(new MailerErr(err))
} else {
next()
}
})
问题2:
在对数据进行任何类型的操作之前,我是否需要清理req.body,即使它没有持久存储到任何数据库.
例如,在我检查验证中间件中是否(payload.question){…}之前,还是在使用pm2.sendDataToProcessId方法发送有效负载之前?
我担心即使没有数据持久存在,也可以从客户端传递函数并在后端执行.
问题3
如果以上确实存在安全风险,我可以简单地在req.body上的链的开头运行一个middlware,以及我可能使用的请求的任何其他部分,转义或删除所有危险字符并有效地解决问题吗?
编辑
我见过验证字段的库,但我不需要广泛的验证解决方案,而是一个简单的卫生解决方案.这就是为什么我想要制作或安装一个中间件,它首先保存req.body或任何其他没有危险字符的数据,然后其他middlwares可以安全地处理数据.
就像是:
清理中间件:
module.exports = (req, res, next) => {
req.body.replace(/[|&;$%@"<>()+,]/g, "")
return next()
}
一些api路线:
api.route('/', sanitise, someMiddleware, (req, res, next) => {
// Now we can safely handle req.body in the middlwares.
})
答案1:是的,用户可以更改任何标题.但不是req.connection.remoteAddress.所以你可能想优先考虑那个.
答案2:是的,逃避字符串和验证数据组合通常是一种很好的做法.您应该在API级别执行此操作.
答案3:我喜欢Joi作为一个很好的API验证包.还有其他套餐可能更适合您的需求.
