Course Content

Joi.js Input Validation (Part 1)

Joi.js Input Validation (Part 1)

Table Of Contents

Scope

  1. Understand how to approach input validation (useful for any input validation library)
  2. Learn how to create json validation schemas within Joi.js

What is Joi?

  • Javascript input validation library
  • Create JSON schemas that validate JSON payloads entering an API (or leaving a browser)

Why Leverage Joi?

  • Very granular whitelisting functionality
    • Define what you will accept from the user
      • Everything else is denied by default

Types Of Input Validation (Question)

  • In general, when user input is sent to the api, what types of input validation should we preform?
    • HINT
      • Think about the different types of coding errors
      • There are two primary types

Types Of Input Validation (Answer)

  • 2 primary checks need to occur when untrusted input (user input) comes to the API
    • If these checks aren't completed, the server might act in unintended ways
  • Types of input validation checks
    1. "Syntactic" Checks (Checking the form of the input)
      • Ex: Is the input a string with length X?
        • Regular Express Denial Of Service (ReDoS) mitigation
      • Usecase for Joi
    2. "Semantic" Checks (Logic Checks)
      • Ex: Does the user have appropriate permissions to do action X?
      • Not what Joi is intended for

Joi Advantages

Joi Advantages (CONT.)

  • Celebrate
    • A Joi validation middleware for Express.js

Joi Schemas

  • Joi leverages schemas to define validations
  • Within a schema, you define types and constraints
    • username: Joi.string().alphanum().min(3).max(30).required()
      1. Type Ex: Joi.string()
        • Joi.string() generates a schema object that matches a string data type
        • Inherits from Joi.any()
          • Generates a schema object that matches any data type
      2. Constraint Ex: .min(3)
        • Each constraint returns a new schema object
        • Method chaining is available

Joi Schemas (CONT.)

  • username: Joi.string().alphanum().min(3).max(30).required()
    • Values (or keys in case of objects) are optional by default

Additional Joi Types

Ex: Joi Bypass (Question)

  • While viewing the following schema object (and payload) on the next slide, think about how it could be exploited/bypassed
  • Further assumptions
    1. JSON payload is submitted to the API
    2. Joi doesn't throw a validation error
    3. The JSON is directly saved to the database
      • Payload key/value pairs are directly mapped to database fields/values
  • Try to figure out how the following schema could be exploited

Ex: Joi Schema/Payload

const Joi = require('joi');

const schema = Joi.object()
  .keys({
    // Requires a given string value
    username: Joi.string()
      .alphanum()
      .min(3)
      .max(30)
      .required(),
    // Define password complexity requirements through regex (consider more complex regex)
    password: Joi.string()
      .regex(/^[a-zA-Z0-9]{3,30}$/)
      .required(),
    // Force passwords to match
    password_confirmation: Joi.any()
      .equal(Joi.ref('password'))
      .required(),
    // Accept different Joi types.  Optional, unconstrained string or number
    access_token: [Joi.string(), Joi.number()],
    // Required birthyear to be an int between range
    birthyear: Joi.number()
      .integer()
      .min(1900)
      .max(2013)
      .required(),
    // Validate email address from example.com (remember spoofing considerations)
    email: Joi.string()
      .email()
      .regex(/example\.com$/),
    marketing_opt_out: Joi.boolean(),
    csrf_token: Joi.string()
      .guid({
        version: 'uuidv4',
      })
      .required(),
    sex: Joi.string()
      .equal(['M', 'F', 'MALE', 'FEMALE', 'DECLINE'])
      .required(),
    time: Joi.date()
      .timestamp('javascript'),
    roles: Joi.object()
      .keys(),
  })
  // email must be accompanied by marketing_opt_out
  .with('email', 'marketing_opt_out');

const result = Joi.validate({
  username: 'Ronald',
  password: 'McDonald',
  password_confirmation: 'McDonald',
  birthyear: 2010,
  email: '[email protected]',
  marketing_opt_out: true,
  csrf_token: '6d4d8c14-ef12-45d9-ab3c-5dddf941fb76',
  sex: 'F',
  time: 1534942475121,
  roles: {},
}, schema);

// If result.error === null, payload is valid
console.log(`The validation error is: ${result.error}`);

Ex: Joi Schema/Payload (Result)

The validation error is: null
Discussion

0 comments