Как Node проверяет достоверность данных на уровне контроллера

Node.js внешний интерфейс

Эта статья включена в блог GitHub Shanyuexing:shfshanyue/blog, который содержит проблемы, с которыми я столкнулся в реальной работе, размышлениях о бизнесе и обучении в направлении полного стека.

Юмористические back-end программисты обычно высмеивают себя как CURD Boy. CURD, то есть добавление, удаление, изменение и проверка ресурса хранения, является полностью ориентированным на данные программированием.

Это здорово, программирование, ориентированное на данные, имеет тенденцию более глубоко понимать бизнес, чтобы писать более качественный код и создавать меньше ошибок. Поскольку это программирование, ориентированное на данные, более необходимо избегать появления грязных данных и усиливать проверку данных. В противном случае нужно ли доверять проверке данных внешнего интерфейса?В конце концов, проверка данных внешнего интерфейса идет непосредственно к пользователю для более удобной обратной связи с пользователем на уровне пользовательского интерфейса.

Слой проверки данных

Серверная часть разделена на различные уровни из-за тяжелой бизнес-логики и различных данных, которые необходимо обработать.Controller,Service,Model,Helper,EntityСуществуют различные именованные слои и так далее. Но здесь определенно есть слой, называемыйController, стоящий на верхнем уровне серверной части, чтобы напрямую получать данные, передаваемые клиентом.

из-заControllerУровень — это верхний уровень взаимодействия данных на стороне сервера с клиентом, придерживающийсяFail FastПринцип , берет на себя функцию фильтра данных и напрямую наносит ответный удар незаконным данным, таким же величественным, как Цинь Цюн и Ючи Гунмэнь.

Проверка данных также создает полудокументированный побочный продукт.Вам нужно только взглянуть на слой проверки данных, чтобы узнать, какие поля и в каком формате передавать.

Ниже приведены общие проверки данных, и в этой статье описывается, как их проверить:

  1. required/optional
  2. Проверка основных данных, таких как число, строка, отметка времени и условия, которым должно соответствовать значение.
  3. Сложная проверка данных, таких как IP, номер мобильного телефона, электронная почта и доменное имя
const body = {
  id,
  name,
  mobilePhone,
  email
}

Shanyue связалась с серверным проектом без уровня проверки данных.if/elseНаполненный различными уровнями, он крайне болезненный, а рефакторится за считанные минуты.

JSON Schema

JSON SchemaФормат проверки данных на основе JSON со спецификациейjson-schema.org, текущая (2020-08) последняя версия — 7.0. Спецификацию реализуют различные серверные языки программирования, такие какgo,java,phpи т. д., конечно, есть и отличные javascripts, такие как tepidajv.

Ниже приведена схема проверки информации о пользователе, видно, что синтаксис сложный и громоздкий:

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "title": "User",
  "description": "用户信息",
  "type": "object",
  "properties": {
    "id": {
      "description": "用户 ID",
      "type": "integer"
    },
    "name": {
      "description": "用户姓名",
      "type": "string"
    },
    "email": {
      "description": "用户邮箱",
      "type": "string",
      "format": "email",
      "maxLength": 20
    },
    "mobilePhone": {
      "description": "用户手机号",
      "type": "string",
      "pattern": "^(?:(?:\+|00)86)?1[3-9]\d{9}$",
      "maxLength": 15
    }
  },
  "required": ["id", "name"]
}

Для проверки сложных типов данных схема JSON имеет следующие встроенные форматы, которые удобно и быстро проверить.

  • Dates and times
  • Email addresses
  • Hostnames
  • IP Addresses
  • Resource identifiers
  • URI template
  • JSON Pointer
  • Regular Expressions

Для мобильных номеров не во встроенном формате используйтеajv.addFormatФормат можно добавить вручную

ajv.addFormat('mobilePhone', (str) => /^(?:(?:\+|00)86)?1[3-9]\d{9}$/.test(str));

Joi

joiСамопровозглашенная самая мощная библиотека проверки JS также получила 16 000 звезд на github. По сравнению со схемой JSON ее синтаксис более краткий и мощный.

The most powerful data validation library for JS

Выполнение той же проверки требует меньше кода и обеспечивает более надежную проверку. Ниже приведен только пример, дополнительные примеры можно найти в документации.

const schema = Joi.object({
  id: Joi.number().required(),
  name: Joi.number().required(),
  email: Joi.string().email({ minDomainSegments: 2, tlds: { allow: ['com', 'net'] } }),
  mobilePhone: Joi.string().pattern(/^(?:(?:\+|00)86)?1[3-9]\d{9}$/),

  password: Joi.string().pattern(/^[a-zA-Z0-9]{3,30}$/),
  // 与 password 相同的校验
  repeatPassword: Joi.ref('password'),
})
  // 密码与重复密码需要同时发送
  .with('password', 'repeat_password');
  // 邮箱与手机号提供一个即可
  .xor('email', 'mobilePhone')

Проверка данных и интеграция уровня маршрутизации

Поскольку данные передаются непосредственно из маршрута,koajsОфициально на основеjoiпонялjoi-router, внешние данные проверяются на уровне маршрутизации, а данные передаются от внешнего интерфейса.query,bodyа такжеparamsПроверьте это.

joi-routerтакже на основеco-bodyРазличные типы передних трансмиссийcontent-typeРазбирать и ограничивать. если ограничитьсяapplication/json, он также может в определенной степени предотвратить атаки CSRF.

const router = require('koa-joi-router');
const public = router();

public.route({
  method: 'post',
  path: '/signup',
  validate: {
    header: joiObject,
    query: joiObject,
    params: joiObject,
    body: joiObject,
    maxBody: '64kb',
    output: { '400-600': { body: joiObject } },
    type: 'json',
    failure: 400,
    continueOnError: false
  },
  pre: async (ctx, next) => {
    await checkAuth(ctx);
    return next();
  },
  handler: async (ctx) => {
    await createUser(ctx.request.body);
    ctx.status = 201;
  },
});

Регулярные выражения и безопасные регулярные выражения

Когда Шаньюэ исследовал проблемы с производительностью, он обнаружил, что API занимает слишком много времени на уровне проверки данных, о чем я никогда не думал. Корень проблемы лежит в небезопасных регулярных выражениях, так что же такое небезопасное регулярное выражение?

Например, приведенное ниже регулярное выражение, которое может повесить ЦП, — это бомба замедленного действия, а количество возвратов вошло в экспоненциальный взрыв.

Вы можете обратиться к статьеАнализ принципа и практики Redos

const safe = require('safe-regex')
const re = /(x+x+)+y/

// 能跑死 CPU 的一个正则
re.test('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')

// 使用 safe-regex 判断正则是否安全
safe(re)   // false

Верификация данных в основном направлена ​​на проверку строк, а также насыщена различными регулярными выражениями, очень важно обеспечить безопасность регулярных выражений.safe-regexМожет обнаружить, какие небезопасные регулярные выражения.

Суммировать

  1. Уровень контроллера должен выполнять унифицированную проверку данных и может использовать схему JSON (узел реализует ajv) и Joi.
  2. У JSON Schema есть официальные спецификации и реализации на разных языках, но синтаксис громоздкий, можно использовать Joi, у которого более мощная функция проверки.
  3. При проверке строки обратите внимание на проблемы с производительностью, вызванные небезопасным