All Projects → dubzzz → fuzz-rest-api

dubzzz / fuzz-rest-api

Licence: MIT license
Derive property based testing fast-check into a fuzzer for REST APIs

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to fuzz-rest-api

Rapid
Rapid is a Go library for property-based testing that supports state machine ("stateful" or "model-based") testing and fully automatic test case minimization ("shrinking")
Stars: ✭ 213 (+460.53%)
Mutual labels:  quickcheck, property-based-testing, fuzzing
Fast Check
Property based testing framework for JavaScript (like QuickCheck) written in TypeScript
Stars: ✭ 2,604 (+6752.63%)
Mutual labels:  quickcheck, property-based-testing, fuzzing
Jqf
JQF + Zest: Coverage-guided semantic fuzzing for Java.
Stars: ✭ 340 (+794.74%)
Mutual labels:  quickcheck, property-based-testing, fuzzing
quickcheck
Randomized testing for Prolog à la QuickCheck
Stars: ✭ 18 (-52.63%)
Mutual labels:  quickcheck, property-based-testing
Quicktheories
Property based testing for Java 8
Stars: ✭ 483 (+1171.05%)
Mutual labels:  quickcheck, property-based-testing
Haskell Hedgehog
Release with confidence, state-of-the-art property testing for Haskell.
Stars: ✭ 584 (+1436.84%)
Mutual labels:  quickcheck, property-based-testing
kitimat
A library for generative, property-based testing in TypeScript and Jest.
Stars: ✭ 68 (+78.95%)
Mutual labels:  quickcheck, property-based-testing
Qcstm
A simple state-machine framework for OCaml based on QCheck
Stars: ✭ 50 (+31.58%)
Mutual labels:  quickcheck, property-based-testing
Junit Quickcheck
Property-based testing, JUnit-style
Stars: ✭ 821 (+2060.53%)
Mutual labels:  quickcheck, property-based-testing
Swiftcheck
QuickCheck for Swift
Stars: ✭ 1,319 (+3371.05%)
Mutual labels:  quickcheck, property-based-testing
Quickcheck State Machine
Test monadic programs using state machine based models
Stars: ✭ 192 (+405.26%)
Mutual labels:  quickcheck, property-based-testing
Qcheck
QuickCheck inspired property-based testing for OCaml.
Stars: ✭ 194 (+410.53%)
Mutual labels:  quickcheck, property-based-testing
edd
Erlang Declarative Debugger
Stars: ✭ 20 (-47.37%)
Mutual labels:  quickcheck, property-based-testing
Stream data
Data generation and property-based testing for Elixir. 🔮
Stars: ✭ 597 (+1471.05%)
Mutual labels:  quickcheck, property-based-testing
pbt-frameworks
An overview of property-based testing functionality
Stars: ✭ 29 (-23.68%)
Mutual labels:  quickcheck, property-based-testing
Quick check.js
A JS implementation of quick_check
Stars: ✭ 48 (+26.32%)
Mutual labels:  quickcheck, property-based-testing
ava-fast-check
Property based testing for AVA based on fast-check
Stars: ✭ 44 (+15.79%)
Mutual labels:  quickcheck, property-based-testing
efftester
Effect-Driven Compiler Tester for OCaml
Stars: ✭ 37 (-2.63%)
Mutual labels:  quickcheck, property-based-testing
Rantly
Ruby Imperative Random Data Generator and Quickcheck
Stars: ✭ 241 (+534.21%)
Mutual labels:  quickcheck, property-based-testing
Fsharp Hedgehog
Release with confidence, state-of-the-art property testing for .NET.
Stars: ✭ 219 (+476.32%)
Mutual labels:  quickcheck, property-based-testing

Wikipedia defines Fuzzing as:

Fuzzing or fuzz testing is an automated software testing technique that involves providing invalid, unexpected, or random data as inputs to a computer program. The program is then monitored for exceptions such as crashes, or failing built-in code assertions or for finding potential memory leaks.

This repository derives a property based testing framework called fast-check into a fuzzing system.

Steps to run this code locally:

git clone https://github.com/dubzzz/fuzz-rest-api.git
cd fuzz-rest-api
npm install
npm run start #launch a webserver on port 8080
npm run test  #run the 'fuzzing'

It intentially comes with an unsafe implementation of its APIs.

  • /api/login - does not escape incoming parameters from POST
  • /api/profile/:uid - considers uid to be an integer while its not

How does it work?

This Proof-Of-Concept uses the power of property based testing to generate inputs for a REST end-point. It sends the generated values to this end-point and check for the property - whatever the data I send I should not receive an Internal Error aka 500.

Basically defining the REST inputs using fast-check is quite simple:

fc.record({
  nameOfFieldOne: fc.string(),
  nameOfFieldTwo: fc.string(),
  nameOfFieldThree: fc.string(),
  //...
  nameOfFieldWithMoreComplexLayout: fc.record({
    subFieldOne: fc.string(),
    //...
  })
})

In the above example nameOfFieldOne, nameOfFieldTwo... are all filled with string values. Depending on your API you may want to be more precise on the types you are using. For instance if nameOfFieldOne expects integers you might prefer fc.integer(). The benefit of specifying the real types is that you may find bugs deaper in your code.

Nonetheless the two approches are fully complementary. Depending on the type safety provided by your back, you may want to check that sending other types will not cause Internal Server Errors like here in /api/profile/:uid route.

One solution to have the better of those two worlds is to use fc.oneof(/*realType, eg.: fc.integer()*/, fc.string()) everywhere you want to specify real type.

You may also use the helper https://github.com/dubzzz/fuzz-rest-api/blob/master/test/inferPayloadArbitrary.js in order to automatically build the arbitrary from a given payload. With this helper, input {min: 9, max: 30, label: 'toto'} will produce the arbitrary fc.record({min: fc.integer(), max: fc.integer(), label: fc.string()}) or the alternative with fc.oneof(...).

Output of test command

npm run test produces the following output:

$ npm run test

> [email protected] test ...
> mocha --require babel-polyfill --require babel-register "test/**/*.js"



  Fuzzing REST API
    1) /api/login
    2) /api/profile/:uid
    3) /api/comment


  0 passing (452ms)
  3 failing

  1) Fuzzing REST API
       /api/login:
     Error: Property failed after 5 tests (seed: 1524328189654, path: 4:0:0:1:0:4): [{"password":"'"}]
Shrunk 5 time(s)
Got error: Error: Internal Server Error, got: {"data":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<title>Error</title>\n</head>\n<body>\n<pre>Error: SQLITE_ERROR: unrecognized token: &quot;&#39;&#39;&#39;&quot;</pre>\n</body>\n</html>\n","status":500}

Stack trace: Error: Internal Server Error, got: {"data":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<title>Error</title>\n</head>\n<body>\n<pre>Error: SQLITE_ERROR: unrecognized token: &quot;&#39;&#39;&#39;&quot;</pre>\n</body>\n</html>\n","status":500}
    at exports.throwIfHttpFailed (test/asyncHttp.js:38:33)
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:188:7)
      at throwIfFailed (node_modules\fast-check\src\check\runner\utils\utils.ts:146:11)
      at <anonymous>
      at process._tickCallback (internal/process/next_tick.js:188:7)

  2) Fuzzing REST API
       /api/profile/:uid:
     Error: Property failed after 1 tests (seed: 1524328189825, path: 0:1:0:0:0): ["\u0000"]
Shrunk 4 time(s)
Got error: Error: Internal Server Error, got: {"data":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<title>Error</title>\n</head>\n<body>\n<pre>Error: SQLITE_ERROR: near &quot;=&quot;: syntax error</pre>\n</body>\n</html>\n","status":500}

Stack trace: Error: Internal Server Error, got: {"data":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<title>Error</title>\n</head>\n<body>\n<pre>Error: SQLITE_ERROR: near &quot;=&quot;: syntax error</pre>\n</body>\n</html>\n","status":500}
    at exports.throwIfHttpFailed (test/asyncHttp.js:38:33)
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:188:7)
      at throwIfFailed (node_modules\fast-check\src\check\runner\utils\utils.ts:146:11)
      at <anonymous>
      at process._tickCallback (internal/process/next_tick.js:188:7)

  3) Fuzzing REST API
       /api/comment:
     Error: Property failed after 17 tests (seed: 1524328189856, path: 16:0:2:3:4:4:4:4): [{"user":{"login":""},"comment":{"postId":0,"commentId":""}}]
Shrunk 7 time(s)
Got error: Error: Internal Server Error, got: {"data":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<title>Error</title>\n</head>\n<body>\n<pre>Error: Supposed it failed on this case<br> &nbsp; &nbsp;at router.post.wrap (src/server.js:62:61)<br> &nbsp; &nbsp;at node_modules/async-middleware/dist/index.js:18:23<br> &nbsp; &nbsp;at Layer.handle [as handle_request] (node_modules/express/lib/router/layer.js:95:5)<br> &nbsp; &nbsp;at next (node_modules/express/lib/router/route.js:137:13)<br> &nbsp; &nbsp;at Route.dispatch (node_modules/express/lib/router/route.js:112:3)<br> &nbsp; &nbsp;at Layer.handle [as handle_request] (node_modules/express/lib/router/layer.js:95:5)<br> &nbsp; &nbsp;at node_modules/express/lib/router/index.js:281:22<br> &nbsp; &nbsp;at Function.process_params (node_modules/express/lib/router/index.js:335:12)<br> &nbsp; &nbsp;at next (node_modules/express/lib/router/index.js:275:10)<br> &nbsp; &nbsp;at Function.handle (node_modules/express/lib/router/index.js:174:3)</pre>\n</body>\n</html>\n","status":500}

Stack trace: Error: Internal Server Error, got: {"data":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<title>Error</title>\n</head>\n<body>\n<pre>Error: Supposed it failed on this case<br> &nbsp; &nbsp;at router.post.wrap (src/server.js:62:61)<br> &nbsp; &nbsp;at node_modules/async-middleware/dist/index.js:18:23<br> &nbsp; &nbsp;at Layer.handle [as handle_request] (node_modules/express/lib/router/layer.js:95:5)<br> &nbsp; &nbsp;at next (node_modules/express/lib/router/route.js:137:13)<br> &nbsp; &nbsp;at Route.dispatch (node_modules/express/lib/router/route.js:112:3)<br> &nbsp; &nbsp;at Layer.handle [as handle_request] (node_modules/express/lib/router/layer.js:95:5)<br> &nbsp; &nbsp;at node_modules/express/lib/router/index.js:281:22<br> &nbsp; &nbsp;at Function.process_params (node_modules/express/lib/router/index.js:335:12)<br> &nbsp; &nbsp;at next (node_modules/express/lib/router/index.js:275:10)<br> &nbsp; &nbsp;at Function.handle (node_modules/express/lib/router/index.js:174:3)</pre>\n</body>\n</html>\n","status":500}
    at exports.throwIfHttpFailed (test/asyncHttp.js:38:33)
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:188:7)
      at throwIfFailed (node_modules\fast-check\src\check\runner\utils\utils.ts:146:11)
      at <anonymous>
      at process._tickCallback (internal/process/next_tick.js:188:7)

It detects:

  • sql injection in /api/login with counterexample: {"password":"'"}
  • sql injection in /api/profile/:uid with :uid: \u0000
  • implementation problem in /api/comment with counterexample: {"user":{"login":""},"comment":{"postId":0,"commentId":""}}
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].