我有一个带有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验证包.还有其他套餐可能更适合您的需求.