【问题标题】:Joi extension for escaping html tags用于转义 html 标签的 Joi 扩展
【发布时间】:2021-11-18 20:31:04
【问题描述】:

我想创建一个扩展来清理字符串输入并去除 html 标签。

为此,我使用sanitize-html npm 包。

这是我迄今为止尝试过的。

const sanitizeHtml = require('sanitize-html');

module.exports = function htmlStrip(joi) {
  return {
    type: 'htmlStrip',
    base: joi.string(),
    messages: {
      htmlStrip: 'Should not contain any html tags.',
    },
    validate(value, helpers) {
      const clean = sanitizeHtml(value, {
        allowedTags: [],
        allowedAttributes: {},
      });
      if (clean) {
        return clean;
      }
      return { value, errors: helpers.error('htmlStrip') };
    },
  };
};

但我遇到了错误。

TypeError: Joi.string(...).trim(...).htmlStrip 不是函数

我也尝试过如下传递规则对象,但仍然遇到同样的错误。

const sanitizeHtml = require('sanitize-html');

module.exports = function htmlStrip(joi) {
  return {
    type: 'htmlStrip',
    base: joi.string(),
    messages: {
      htmlStrip: 'Should not contain any html tags.',
    },
    rules: {
      htmlStrip: {
        validate(params, value, state, options) {
          const clean = sanitizeHtml(value, {
            allowedTags: [],
            allowedAttributes: {},
          });
          if (clean) {
            return clean;
          }
          return this.createError('string.htmlStrip', { value }, state, options);
        },
      },
    },
  };
};

我正在关注here 提到的文档。

这就是我使用扩展验证器的方式。

const Joi = require('@hapi/joi').extend(require('@hapi/joi-date')).extend(require('../utils/sanitize-html-joi'));

const validateAddressCreateData = (data) => {
  const schema = Joi.object({
    address: Joi.string().trim().htmlStrip().required(),
    label: Joi.string()
      .required(),
  });
  return schema.validate(data);
};

【问题讨论】:

  • 请包含完整的错误堆栈。这样可以更容易地查看错误的来源。
  • @Molda 添加了弹出错误的代码。

标签: javascript node.js joi


【解决方案1】:

不知道为什么你假设Joi.string().trim() 的类型与Joi 相同,考虑到你扩展了Joi 对象,但期望htmlStripJoi.string().trim() 结果中可用。

两种类型的简单 console.log 表明它们是不同的类型。

console.log(Object.keys(Joi)):

[ '_types',
  'alternatives',
  'any',
  'array',
  'boolean',
  ...
  'htmlStrip' ]

console.log(Object.keys(Joi.string().trim());:

[ 'type',
  '$_root',
  '$_temp',
  '_ids',
  '_preferences',
  '_valids',
  '_invalids',
  '_rules',
  '_singleRules',
  '_refs',
  '_flags',
  '_cache',
  '$_terms',
  '$_super' ]

trim 的结果$_super 似乎不包含任何键,因此它们并不真正相关。

我相信如果你想预处理你的输入并然后使用你的htmlStrip,你必须做这样的事情:

const sanitizeHtml = require('sanitize-html');

module.exports = function htmlStrip(joi) {
  return {
    type: 'htmlStrip',
    base: joi.string(),
    messages: {
      htmlStrip: 'Should not contain any html tags.',
    },
    validate(value, helpers) {
      const clean = sanitizeHtml(value, {
        allowedTags: [],
        allowedAttributes: {},
      });
      if (clean == value) {
        return { clean, errors: [] };
      }
      return { value, errors: helpers.error('htmlStrip') };
    },
  };
};

这是我的使用方法:

const Joi = require('@hapi/joi').extend(require('@hapi/joi-date')).extend(require('./san'));

const validateAddressCreateData = (data) => {
  const schema = Joi.object({
    address: Joi.htmlStrip(Joi.string().trim()).required(),
    label: Joi.string().required(),
  });
  return schema.validate(data);
};

console.log(validateAddressCreateData({ address: "<body>test</body>", label: "abc"}));

但我不确定输出是否如您所愿:

{ value: { address: '<body>test</body>', label: 'abc' },
  error:
   { ValidationError: Should not contain any html tags.
     _original: { address: '<body>test</body>', label: 'abc' },
     details: [ [Object] ] } }

所以,似乎是根据定义的验证消息来验证输入。还是您真的要修改正在传递的地址 html?

编辑现在明白了,相应地修改了htmlStrip。请看比较if(value == clean)。如果 sanitizer 不需要修剪任何东西,这意味着输入字符串不包含任何 html 标签。其他情况返回错误。

【讨论】:

  • 谢谢,但它不起作用。如果我在字符串中发送 html 标签,我没有收到任何验证错误。另外,你是对的,我想在将其传递给 stripHTML 之前附加其他验证。
  • 稍微编辑了输出。你真的想修改传递给验证器的字符串吗?但这在语义上是正确的吗?我相信验证器不应该改变被验证的对象......只需检查它是否正确。
  • 这里有一个问题,这个函数sanitizeHtml 正在清理输入,而不是通知它是否包含一些可用于 XSS 攻击的 html 标签。我不想修改输入,而是想通知用户数据无效。
  • 嗯,我相信错误ValidationError: Should not contain any html tags. 几乎说明了一切,对吧?显然,它确实包含 html 标签。
  • 现在明白了,只需进行比较if(clean == value) - 在这种情况下,消毒剂不必修剪任何东西。相应地编辑了答案。
【解决方案2】:

使用自定义验证导出 Joi 将解决此问题 (custom_joi.js)

const sanitizeHtml = require('sanitize-html');
const Joi = require('@hapi/joi')

module.exports = Joi.extend((joi) => ({
 type: "string",
 base: joi.string(),
 messages: {
    "string.htmlStrip": "{{#label}} not contain any html tags"
 },
 rules: {
 htmlStrip: {
  validate(value, helpers) {
    const clean = sanitizeHtml(value, {
      allowedTags: [],
      allowedAttributes: {},
    });
    if (clean == value) {
      return clean;
    }
    return helpers.error("string.htmlStrip")
  }
} } } ) )

并在控制器中导入我们的自定义文件

const Joi = require('../../_helpers/custom_joi');

然后创建验证模式

const schema = Joi.object().keys({
notes: Joi.string().htmlStrip().allow('', null),
specialInstructions: Joi.string().htmlStrip()
});
const { error, value } = schema.validate(req.body);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-21
    • 2011-04-19
    • 1970-01-01
    • 2010-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多