如何在Node.js中对输入值进行清洗处理?

45

我已经对我的Node.js输入进行了验证,以确保它们不为空,但我希望也能进行数据清洗。请帮助我如何实现。

req.checkBody('name', 'Name is required!').notEmpty();
req.checkBody('surname', 'Surname is required!').notEmpty();
req.checkBody('username', 'Username is required!').notEmpty();
req.checkBody('password', 'Password is required!').notEmpty();
req.checkBody('password2', 'Passwords do not match!').equals(req.body.password);

var errors = req.validationErrors();

if (errors) {
    res.render('user/register', {
        errors: errors,
        user: null,
        title: 'Register'
    });
}
else {
    var userData = {
        name : req.body.name,
        surname : req.body.surname,
        username : req.body.username,
        password : req.body.password,
        avatar : 'No_person.jpg'
    };
    userController.addUser(req,res,userData);
}

你可以随时使用 Sequelize 和他们的模型层来定义验证。 - tadman
也许你可以使用:https://github.com/coditorium/nodejs-fluent-validator - Xiaoy312
3
你可以使用Joi框架。 - mehta-rohan
5个回答

59
  • 对于大多数框架,您可以使用sanitize node模块:

 npm install sanitize --save

然后可以像这样使用:

 var sanitizer = require('sanitize')();

 var name = sanitizer.value(req.name, 'string');
 var surname= sanitizer.value(req.surname, 'string');

如需了解更多,请查看 sanitize 文档。

  • 如果您正在使用 express,则可以按照以下方式使用 express-validatorexpress-sanitize-input 包进行验证和净化:

  •  const express = require('express');
     const { check } = require('express-validator');
     const app = express();
    
     app.use(express.json())
    
     app.post('/form', [
       check('name').isLength({ min: 3 }).trim().escape(),
       check('email').isEmail().normalizeEmail(),
       check('age').isNumeric().trim().escape()
     ], (req, res) => {
       const name  = req.body.name
       const email = req.body.email
       const age   = req.body.age
     })  
    

    了解更多信息,可以查看 express-validatorexpress-sanitize-input 文档。

    如果您正在使用 Hapi,则可以使用Joi进行验证和清理,使用Joi可以通过附加选项清洁变量。

     validate(value, schema, {escapeHtml: true}, [callback])
    

    查看更多信息,请参阅Joi文档。

  • 如果您不想使用任何第三方模块,并且想使用内置的node来进行净化,可以尝试以下操作:

  •  // For string variables
     str = typeof(str) === 'string' && str.trim().length > 0 ? str.trim() : '';
     // for boolean values
     bool = typeof(bool) === 'boolean' && bool === true ? true : false;
     // for array values
     arr = typeof(arr) === 'object' && arr instanceof Array ? arr : [];
     // for number values
     num = typeof(num) === 'number' && num % 1 === 0 ? num : 0;
     // for objects
     obj = typeof(obj) === 'object' && !(obj instanceof Array) && obj !== null ? obj : {};
    

    @V.Aleksanyan,这里的“string”是指您想要匹配的值或允许的正则表达式。您可以在sanitizer runkit中尝试它。 - kgangadhar
    当我提交表单时,我会检查验证并编写您的代码: var name = sanitizer.value(req.body.name, 'string'); var name = sanitizer.value(req.body.surname, 'string'); var name = sanitizer.value(req.body.username, 'string'); 它返回了这个错误“字符串不是有效的净化器类型”。请告诉我为什么? - V.Aleksanyan
    1
    这只是一个示例,展示它的工作原理,应该像这样 var myMatchingString = sanitizer.value(req.mystring, /abc123/); 或者使用正则表达式而不是 abc123,请查看文档,它将解释如何将其用作应用程序中间件。 - kgangadhar
    check() 不是 Express 内置的函数。它是 express-validator 的一部分。 - sloreti
    在变量name中,使用了不合法的sanitizer类型,报错"string is not a valid sanitizer type"。请检查代码中req.name的值是否符合要求。 - abhinav1602

    10

    实际上,我写了一个包来轻松解决这个问题。您可以在Github上使用它或为其做出贡献。

    从这里下载此程序包:https://www.npmjs.com/package/string-sanitizer

    您可以使用此实用程序包对英语以外的其他语言进行消毒处理。在库内部,使用正则表达式。您可以将字符串转换为URL或文件名友好字符串。以下是应用案例:

    var string = require("string-sanitizer");
    
    string.sanitize("a.bc@d efg#h"); // abcdefgh
    string.sanitize.keepSpace("a.bc@d efg#h"); // abcd efgh
    string.sanitize.keepUnicode("a.bc@d efg#hক"); // abcd efghক
    string.sanitize.addFullstop("a.bc@d efg#h"); // abcd.efgh
    string.sanitize.addUnderscore("a.bc@d efg#h"); // abcd_efgh
    string.sanitize.addDash("a.bc@d efg#h"); // abcd-efgh
    string.sanitize.removeNumber("@abcd efgh123"); // abcdefgh
    string.sanitize.keepNumber("@abcd efgh123"); // abcdefgh123
    string.addFullstop("abcd efgh"); // abcd.efgh
    string.addUnderscore("@abcd efgh"); // @abcd_efgh
    string.addDash("@abcd efgh"); // @abcd-efgh
    string.removeSpace("@abcd efgh"); // @abcdefgh
    

    代码块

    输入图像描述


    11
    这个库更像是一个字符串操作库,而不是一个可行的过滤器。过滤应该尽可能地限制输入并最好具有上下文意识,而不仅仅是将字符串操纵成所期望的结果:string.sanitize("1@2.com") 理想情况下不应返回 "12com"。一些改进可以包括专注于上下文特定的过滤(如 sanitize.HTMLsafe()sanitize.SQLsafe()sanitize.EmailAddress() 等),以及放弃字符串辅助函数(把厨房水槽留在家里)。 - PotatoFarmer
    8
    感谢您的建议。基本上,我写这篇文章是为了解决一个实际问题。自那以后,很多人发现它非常方便和有用。在我们的实际生活中,“Sanitizer”的意思是清洁或消毒。这个词在实际意义上被使用。除此之外,“string-manipulator”和“string-manipulation”这两个名称在发布这个库时已经被占用了。我会尝试在未来加入这些更新。再次感谢您。 - Md Fazlul Karim
    1
    到目前为止,我认为这是解决清理问题的最佳方法。我不想知道输入是什么。就像js可以检测整数和字符串一样,我认为它应该工作,并且这已经相当接近了。问题在于通过修剪添加到输入值之前或之后的不需要的符号来避免SQL注入。 - Jerubaal Xerxes

    0

    validator每周有500万次下载,似乎是目前行业中最受欢迎的包。express-validator使用validator作为其核心。这些肯定是一种选择,还有其他包,如xsssanitize-html

    这两个验证器包都有广泛的文档,以下是有关净化的部分:

    https://express-validator.github.io/docs/sanitization.html


    0

    我使用Yup进行验证。它比Joi包要小得多。我在前端和后端都使用Yup,并且通常将我的验证放入一个共享的npm包中,使得前端和后端项目都可以使用相同的验证库。

    npm install -S yup
    

    那么

    import * as yup from 'yup';
    
    let schema = yup.object().shape({
      name: yup.string().required(),
      age: yup.number().required().positive().integer(),
      email: yup.string().email(),
      website: yup.string().url(),
      createdOn: yup.date().default(function () {
        return new Date();
      }),
    });
    
    // check validity
    schema
      .isValid({
        name: 'jimmy',
        age: 24,
      })
      .then(function (valid) {
        valid; // => true
      });
    

    来自Yup网站:

    Yup是一个JavaScript模式生成器,用于值解析和验证。定义一个模式,将值转换为匹配项,验证现有值的形状或两者兼而有之。Yup模式非常具有表现力,可以建模复杂的、相互依赖的验证或值转换。

    Yup的API受Joi的启发,但更加精简,并以客户端验证为主要用例构建。Yup将解析和验证函数分成单独的步骤。cast()转换数据,而validate检查输入是否正确。它们可以一起执行(例如HTML表单验证)或分开执行(例如从API反序列化可信数据)。

    您可能需要为特殊项目(如密码匹配等)创建自己的验证器。这可以使用正则表达式完成,然后像这样将函数添加到Yup中:

    let schema = string().matches(/(hi|bye)/);
    

    将所有验证函数(包括 TypeScript 类型等)放入共享的 NPM 包中。这样,前端团队与后端验证不同步的情况就会变得不那么令人担忧了。

    0
    您可以创建自定义中间件,将其集成到任何端点(或全局应用于每个请求),并检查请求体中的任何输入是否存在问题。
    它将会检查以下内容:
    - 输入是否包含嵌入的HTML代码(例如脚本或图像)。 - 第一个非空白字符是否为=,这可能导致Excel导入存在漏洞。

    中间件

    const containsHtml = /<[^>]*>/;
    const startsWithEqual = /^\s*=/;
    
    const isInvalidInput = (input) => {
      return containsHtml.test(input) || startsWithEqual.test(input);
    }
    
    exports.inputValidator = (req,res,next) => {
      let invalid_input_count = 0;
      const obj = req.body;
      const stack = [obj];
      while (stack?.length > 0) {
        const currentObj = stack.pop();
        Object.keys(currentObj).forEach(key => {
          if (typeof currentObj[key] === 'object' && currentObj[key] !== null) {
            stack.push(currentObj[key]);
          } else {
            if (typeof currentObj[key] === 'string' && isInvalidInput(currentObj[key])) {
              invalid_input_count++;
            }
          }
        });
      }
    
      if(invalid_input_count === 0) {
        return next();
      } else{
        return res.status(400).json({ success: false, error_code: 'invalid_input'});
      }
    }
    

    用法

    const express = require('express');
    const { inputValidator } = require('./util/input-validator');
    
    ...
    
    const app = express();
    app.use(inputValidator); // Check every request for vulnerable inputs 
    

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接