gojtp

package module
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 11, 2021 License: MIT Imports: 3 Imported by: 0

README

GOJTP
GoDoc

⚡️ A high-performance, zero allocation, dynamic JSON Threat Protection in pure Go. 🔥

Package gojtp provides a fast way to validate the dynamic JSON and protect against vulnerable JSON content-level attacks (JSON Threat Protection) based on configured properties.

It also validate the JSON and if JSON is Invalid it will return an error.

What is JSON Threat Protection

JSON requests are susceptible to attacks characterized by unusual inflation of elements and nesting levels. Attackers use recursive techniques to consume memory resources by using huge json files to overwhelm the parser and eventually crash the service.

JSON threat protection is terms that describe the way to minimize the risk from such attacks by defining few limits on the json structure like length and depth validation on a json, and helps protect your applications from such intrusions.

There are situations where you do not want to parse the JSON, but do want to ensure that the JSON is not going to cause a problem. Such as an API Gateway. It would be a PAIN for the gateway to have to know all JSON schema of all services it is protecting. There are XML validators that perform similar functions.

Getting Started

Installing To start using gojtp, install Go and run go get:

$ go get -u github.com/ankur-anand/gojtp

Performance

On linux-amd64

BenchmarkTestifyNoThreatInBytes-4         500000              2628 ns/op               0 B/op          0 allocs/op

JSON Used

{
    "simple_string": "hello word",
    "targets": [
        {
            "req_per_second": 5,
            "duration_of_time": 1,
            "utf8Key": "Hello, 世界",
            "request": {
                "endpoint": "https://httpbin.org/get",
                "http_method": "GET",
                "payload": {
                    "username": "ankur",
                    "password": "ananad"
                },
                "array_value": [
                    "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstv"
                ],
                "additional_header": [
                    {
                        "header_key": "uuid",
                        "header_value": [
                            "1",
                            "2"
                        ]
                    }
                ]
            }
        },
        {
            "req_per_second": 10,
            "duration_of_time": 1,
            "request": {
                "endpoint": "https://httpbin.org/post",
                "http_method": "POST",
                "payload": {
                    "username": "ankur",
                    "password": "ananad"
                },
                "additional_header": [
                    {
                        "header_key": "uuid",
                        "header_value": [
                            "1",
                            "2",
                            "3",
                            "4",
                            "5",
                            "Hello, 世界"
                        ]
                    }
                ]
            }
        }
    ]
}

Create a verify

All the verifier Parameters are Optional

Check Godoc for all option

Example Verify

// with multiple config
	_, _ = New(WithMaxArrayElementCount(6),
		WithMaxContainerDepth(7),
		WithMaxObjectKeyLength(20), WithMaxStringLength(50),
		)

	// with single config
	_, _ = New(WithMaxStringLength(25))

Errors

The JTP returns following error messages on Validation failure:

Error Message
jtp.maxStringValueLengthReached.Max-[X]-Allowed.Found-[Y].
jtp.maxArrayElementCountReached.Max-[X]-Allowed.Found-[Y].
jtp.maxKeyLengthReached.Max-[X]-Allowed.Found-[Y]
jtp.maxContainerDepthReached.Max-[X]-Allowed.Found-[Y]
jtp.maxObjectEntryCountReached.Max-[X]-Allowed.Found-[Y]
jtp.MalformedJSON

Usage Example

package main

import (
	"github.com/ankur-anand/gojtp"
	"log"
)

func main() {
	    json := _getTestJsonBytes()
	    verifier1, err := New(WithMaxArrayElementCount(6),
    		WithMaxContainerDepth(7),
    		WithMaxObjectKeyLength(20), WithMaxStringLength(50),
    		)
    	ok, err := verifier1.VerifyBytes(json)
    
    	verifier2, err := New(WithMaxStringLength(25))
    	ok, err = verifier2.VerifyBytes(json)
    	fmt.Println(ok, err)
}

func _getTestJsonBytes() []byte {
	return []byte(`{
	"simple_string": "hello word",
    "targets": [
      {
        "req_per_second": 5,
        "duration_of_time": 1,
		"utf8Key": "Hello, 世界",
        "request": {
          "endpoint": "https://httpbin.org/get",
          "http_method": "GET",
          "payload": {
            "username": "ankur",
            "password": "ananad"
          },
		  "array_value": [
				"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstv"
			],
          "additional_header": [
            {
              "header_key": "uuid",
              "header_value": [
                "1",
                "2"
              ]
            }
          ]
        }
      },
      {
        "req_per_second": 10,
        "duration_of_time": 1,
        "request": {
          "endpoint": "https://httpbin.org/post",
          "http_method": "POST",
          "payload": {
            "username": "ankur",
            "password": "ananad"
          },
          "additional_header": [
            {
              "header_key": "uuid",
              "header_value": [
                "1",
                "2",
				"3",
				"4",
				"5",
				"Hello, 世界"
              ]
            }
          ]
        }
      }
    ]
}
	`)
}

Contact

Ankur Anand @in_aanand

License

GOJTP source code is available under the MIT License.

Based on Parser from tidwall.

Documentation

Overview

Package gojtp provides a fast way to validate the JSON and protect against vulnerable JSON content-level attacks (JSON Threat Protection) based on configured properties.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrInvalidJSON denotes JSON is Malformed
	ErrInvalidJSON = errors.New("jtp.MalformedJSON")
)

Functions

This section is empty.

Types

type Option

type Option func(*Verify) error

Option Function Parameters to creates verifier

func WithMaxArrayElementCount

func WithMaxArrayElementCount(l int) Option

WithMaxArrayElementCount Option Specifies the maximum number of entries ( comma delimited values) allowed in an array. zero value disable the check.

func WithMaxContainerDepth

func WithMaxContainerDepth(l int) Option

WithMaxContainerDepth Option Specifies the maximum allowed nested containers depth, within a JSON where the containers are objects or arrays. zero value disable the checks

func WithMaxObjectEntryCount

func WithMaxObjectEntryCount(l int) Option

WithMaxObjectEntryCount Option Specifies the maximum number of entries (comma delimited string:value pairs) in a single object zero value disable the checks

func WithMaxObjectKeyLength

func WithMaxObjectKeyLength(l int) Option

WithMaxObjectKeyLength Option Specifies the maximum number of characters (UTF-8 encoded) allowed for a property(key) name within an object. zero value disable the checks

func WithMaxStringLength

func WithMaxStringLength(l int) Option

WithMaxStringLength Option Specifies the maximum number of characters ( UTF-8 encoded) in a string value. zero value disable the checks

type Verifier

type Verifier interface {
	VerifyBytes([]byte) (bool, error)
	VerifyString(string) (bool, error)
}

Verifier is the interface that wraps the basic Verify, VerifyBytes and VerifyString methods.

func New

func New(opt ...Option) (Verifier, error)

New creates and return an Verifier with passed Option Parameters, with default UTF-8 text encoding.

Example
// with multiple config
_, _ = New(WithMaxArrayElementCount(6),
	WithMaxContainerDepth(7),
	WithMaxObjectKeyLength(20), WithMaxStringLength(50))

// with single config
_, _ = New(WithMaxStringLength(25))
Output:

type Verify

type Verify struct {
	// Specifies the maximum number of elements allowed in an array.
	MaxArrayElementCount int

	// Specifies the maximum allowed containment depth,
	// where the containers are objects or arrays.
	JSONContainerDepth int

	// Specifies the maximum number of entries allowed in an object
	ObjectEntryCount int

	// Specifies the maximum string length
	// allowed for a property name within an object.
	ObjectKeyLength int

	// Specifies the maximum length allowed for a string value.
	StringValueLen int
	// contains filtered or unexported fields
}

Verify Configuration Parameters. Verify must be created with New function.

 // with some options
	  _, _ = New(
	  		 WithMaxArrayElementCount(6),
			 WithMaxContainerDepth(7),
			 WithMaxObjectKeyLength(20), WithMaxStringLength(50),
			 )

  // with single option
		_, _ = New(WithMaxStringLength(25))

Exported variable are for logging and reference.

func (Verify) VerifyBytes

func (v Verify) VerifyBytes(json []byte) (bool, error)

VerifyBytes returns true if the input is valid json, and is JSON THREAT Protection Safe. A successful VerifyBytes returns err == nil, Callers should treat a return of true and nil as only success case.

Example
json := []byte(`{
	"simple_string": "hello word",
    "targets": [
      {
        "req_per_second": 5,
        "duration_of_time": 1,
		"utf8Key": "Hello, 世界",
        "request": {
          "endpoint": "https://httpbin.org/get",
          "http_method": "GET",
          "payload": {
            "username": "ankur",
            "password": "ananad"
          },
		  "array_value": [
				"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstv"
			],
          "additional_header": [
            {
              "header_key": "uuid",
              "header_value": [
                "1",
                "2"
              ]
            }
          ]
        }
      },
      {
        "req_per_second": 10,
        "duration_of_time": 1,
        "request": {
          "endpoint": "https://httpbin.org/post",
          "http_method": "POST",
          "payload": {
            "username": "ankur",
            "password": "ananad"
          },
          "additional_header": [
            {
              "header_key": "uuid",
              "header_value": [
                "1",
                "2",
				"3",
				"4",
				"5",
				"Hello, 世界"
              ]
            }
          ]
        }
      }
    ]
}
	`)

verifier1, err := New(WithMaxArrayElementCount(6),
	WithMaxContainerDepth(7),
	WithMaxObjectKeyLength(20), WithMaxStringLength(50))
ok, err := verifier1.VerifyBytes(json)

verifier2, err := New(WithMaxStringLength(25))
ok, err = verifier2.VerifyBytes(json)
fmt.Println(ok, err)
Output:

false jtp.maxStringValueLengthReached.Max-[25]-Allowed.Found-[47]

func (Verify) VerifyString

func (v Verify) VerifyString(json string) (bool, error)

VerifyString returns true if the input is valid json, and is JSON THREAT Protection Safe. A successful VerifyString returns err == nil, Callers should treat a return of true and nil as only success case.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL