Security News
The Push to Ban Ransom Payments Is Gaining Momentum
Ransomware costs victims an estimated $30 billion per year and has gotten so out of control that global support for banning payments is gaining momentum.
toxy
Advanced tools
Readme
toxy is a hackable HTTP proxy to simulate failure scenarios and unexpected conditions.
It was mainly designed for fuzz/evil testing purposes, becoming particulary useful to cover fault tolerant and resiliency capabilities of a system, tipically in service-oriented distributed architectures, where toxy
may act as intermediate proxy among services.
toxy allows you to plug in poisons, optionally filtered by rules, which basically can intercept and alter the HTTP flow as you want, performing multiple evil actions in the middle of that process, such as limiting the bandwidth, delaying TCP packets, injecting network jitter latency or replying with a custom error or status code.
Runs in node.js/io.js. Compatible with connect/express. Built on top of rocky, a full-featured, middleware-oriented HTTP/S proxy.
Requires node.js +0.12 or io.js +1.6
There're some other similar solutions to toxy
in the market, but most of them don't provide a proper programmatic control and are not easy to hack, configure and/or extend. Additionally, most of the those solutions are based only on the TCP stack only instead of providing more features to the scope of HTTP applicacion level protocol, like toxy does.
toxy
provides a powerful hacking-driven and extensible solution with a convenient low-level interface and extensible programmatic control, serveds with a simple and fluent API and the power, simplicity and fun of node.js.
toxy
introduces two main core directives worth knowing before using it:
Poisons are the specific logic to infect an incoming or outgoing HTTP flow (e.g: injecting a latency, replying with an error). HTTP flow can be poisoned by one or multiple poisons, and you can plug in poisons at global or route level.
Rules are a kind of validation filters that are applied to the whole global HTTP flow or to a concrete poison, in order to determine if one or multiple poisons should be enabled or not to infect the HTTP traffic (e.g: match headers, query params, method...).
â ( Incoming request ) â
â ||| â
â ---------------- â
â | Toxy Router | â --> Match a route based on the incoming request
â ---------------- â
â ||| â
â ---------------- â
â | Exec Rules | â --> Apply configured rules for the request
â ---------------- â
â ||| â
â ---------------- â
â | Exec Poisons | â --> If all rules passed, poisoning the HTTP flow
â ---------------- â
â / \ â
â \ / â
â ------------------- â
â | HTTP dispatcher | â --> Proxy the HTTP traffic for both poisoned or not
â ------------------- â
npm install toxy
See the examples directory for more use cases
var toxy = require('toxy')
var poisons = toxy.poisons
var rules = toxy.rules
var proxy = toxy()
proxy
.forward('http://httpbin.org')
proxy
.poison(poisons.latency({ jitter: 500 }))
.rule(rules.random(50))
.poison(poisons.bandwidth({ bps: 1024 }))
.withRule(rules.method('GET'))
proxy.get('/*')
proxy.listen(3000)
Poisons host specific logic which intercepts and mutates, wraps, modify and/or cancel an HTTP transaction in the proxy server. Poisons can be applied to incoming or outgoing, or even both traffic flows.
Poisons can be composed and reused for different HTTP scenarios. They are executed in FIFO order and asynchronously.
Name: latency
Infects the HTTP flow injecting a latency jitter in the response
Arguments:
object
number
- Jitter value in milisecondsnumber
- Random jitter maximum valuenumber
- Random jitter minimum valuetoxy.poison(toxy.poisons.latency({ jitter: 1000 }))
// Or alternatively using a random value
toxy.poison(toxy.poisons.latency({ max: 1000, min: 100 }))
Name: inject
Injects a custom response, intercepting the request before sending it to the target server. Useful to inject errors originated in the server.
Arguments:
object
number
- Response HTTP status codeobject
- Optional headers to sendmixed
- Optional body data to sendstring
- Body encoding. Default to utf8
toxy.poison(toxy.poisons.inject({
code: 503,
body: '{"error": "toxy injected error"}',
headers: {'Content-Type': 'application/json'}
}))
Name: bandwidth
Limits the amount of bytes sent over the network in outgoing HTTP traffic for a specific threshold time frame.
Arguments:
object
number
- Bytes per secondsnumber
- Threshold time frame in milisecondstoxy.poison(toxy.poisons.bandwidth({ bps: 1024 }))
Name: rateLimit
Limits the amount of requests received by the proxy in a specific threshold time frame. Designed to test API limits. Exposes the X-RateLimit-*
headers.
Limits are stored in-memory, meaning they are volalite and therfore flushed on every server stop.
Arguments:
object
number
- Total amount of requestnumber
- Limit threshold time frame in miliseconds.string
- Optional error message when limit reached.number
- HTTP status code when limit reached. Default to 429.toxy.poison(toxy.poisons.rateLimit({ limit: 10, threshold: 1000 }))
Name: slowRead
Reads incoming payload data packets slowly. Only valid for non-GET request.
Arguments:
object
number
- Packet chunk size in bytes. Default to 1024
number
- Limit threshold time frame in miliseconds. Default to 1000
toxy.poison(toxy.poisons.slowRead({ chunk: 2048, threshold: 1000 }))
Name: slowOpen
Delays the HTTP connection ready state.
Arguments:
object
number
- Delay connection in miliseconds. Default to 1000
toxy.poison(toxy.poisons.slowOpen({ delay: 2000 }))
Name: slowClose
Delays the HTTP connection close signal.
Arguments:
object
number
- Delay time in miliseconds. Default to 1000
toxy.poison(toxy.poisons.slowClose({ delay: 2000 }))
Name: throttle
Restricts the amount of packets sent over the network in a specific threshold time frame.Arguments:
object
number
- Packet chunk size in bytes. Default to 1024
object
- Limit threshold time frame in miliseconds. Default to 1000
toxy.poison(toxy.poisons.slowRead({ chunk: 2048, threshold: 1000 }))
Name: abort
Aborts the TCP connection, optionally with a custom error. From the low-level perspective, this will destroy the socket on the server, operating only at TCP level without sending any specific HTTP application level data.
Arguments:
number
- Optional socket destroy delay in milisecondstoxy.poison(toxy.poisons.abort())
Name: timeout
Defines a response timeout. Useful when forward to potentially slow servers.
Arguments:
number
- Timeout limit in milisecondstoxy.poison(toxy.poisons.timeout(5000))
Poisons are implemented as standalone middleware (like in connect/express).
Here's a simple example of a server latency poison:
function latency(delay) {
/**
* We name the function since toxy uses it as identifier to get/disable/remove it in the future
*/
return function latency(req, res, next) {
var timeout = setTimeout(clean, delay)
req.once('close', onClose)
function onClose() {
clearTimeout(timeout)
next('client connection closed')
}
function clean() {
req.removeListener('close', onClose)
next()
}
}
}
// Register and enable the poison
toxy
.get('/foo')
.poison(latency(2000))
For featured real example, take a look to the built-in poisons implementation.
Rules are simple validation filters which inspect an HTTP request and determine, given a certain rules (e.g: method, headers, query params), if the HTTP transaction should be poisoned or not.
Rules are useful to compose, decouple and reuse logic among different scenarios of poisoning. You can also define globally applied rules or nested poison-scope rules only.
Rules are executed in FIFO order. Their evaluation logic is equivalent to Array#every()
in JavaScript: all the rules must pass in order to proceed with the poisoning.
Enables the rule by a random probabilistic. Useful for random poisioning.
Arguments:
number
- Percentage of filtering. Default 50
var rule = toxy.rules.probability(85)
toxy.rule(rule)
Filters by HTTP method.
Arguments:
string|array
- Method or methods to filter.var method = toxy.rules.method(['GET', 'POST'])
toxy.rule(method)
Filter by certain headers.
Arguments:
object
- Headers to match by key-value pair. value
can be a string, regexp, boolean
or function(headerValue, headerName) => boolean
var matchHeaders = {
'content-type': /^application/\json/i,
'server': true, // meaning it should be present,
'accept': function (value, key) {
return value.indexOf('text') !== -1
}
}
var rule = toxy.rules.headers(matchHeaders)
toxy.rule(rule)
Filters by content type header. It should be present
Arguments:
string|regexp
- Header value to match.var rule = toxy.rules.contentType('application/json')
toxy.rule(rule)
Match incoming body payload data by string, regexp or custom filter function
Arguments:
string|regexp|function
- Body content to matchstring
- Optional. Body limit in human size. E.g: 5mb
string
- Body encoding. Default to utf8
number
- Body length. Default taken from Content-Length
headervar rule = toxy.rules.body('"hello":"world"')
toxy.rule(rule)
// Or using a filter function returning a boolean
var rule = toxy.rules.body(function (body) {
return body.indexOf('hello') !== -1
})
toxy.rule(rule)
Rules are simple middleware functions that resolve asyncronously with a boolean
value to determine if a given HTTP transaction should be ignored when poisoning.
Your rule must resolve with a boolean
param calling the next(err, shouldIgnore)
function in the middleware, passing a true
value if the rule has not matches and should not apply the poisioning, and therefore continuing with the next middleware stack.
Here's an example of a simple rule matching the HTTP method to determine if:
function method(matchMethod) {
/**
* We name the function since it's used by toxy to identify the rule to get/disable/remove it in the future
*/
return function method(req, res, next) {
var shouldIgnore = req.method !== matchMethod
next(null, shouldIgnore)
}
}
// Register and enable the rule
toxy
.get('/foo')
.rule(method('GET'))
.poison(/* ... */)
For featured real examples, take a look to the built-in rules implementation
toxy
API is completely built on top the rocky API. In other words, you can use any of the methods, features and middleware layer natively provided by rocky
.
Create a new toxy
proxy.
For supported options
, please see rocky documentation
var toxy = require('toxy')
toxy({ forward: 'http://server.net', timeout: 30000 })
toxy
.get('/foo')
.poison(toxy.poisons.latency(1000))
.withRule(toxy.rules.contentType('json'))
.forward('http://foo.server')
toxy
.post('/bar')
.poison(toxy.poisons.bandwidth({ bps: 1024 }))
.withRule(toxy.rules.probability(50))
.forward('http://bar.server')
toxy.all('/*')
Return: ToxyRoute
Return: ToxyRoute
Return: ToxyRoute
Return: ToxyRoute
Return: ToxyRoute
Return: ToxyRoute
Return: ToxyRoute
Alias: usePoison
Alias: useRule
Aliases: poisonRule
, poisonFilter
Return: boolean
Return: boolean
Alias: disablePoisons
Return: array<Directive>
Alias: getPoisons
Alias: flushPoisons
Return: boolean
Return: boolean
Return: array<Directive>
Alias: getRules
Toxy route has, indeed, the same interface as Toxy
global interface, but further actions you perform againts the API will only be applicable at route-level. In other words: good news, you already know the API.
This example will probably clarify possible doubts:
var toxy = require('toxy')
var proxy = toxy()
// Now using the global API
proxy
.poison(toxy.poisons.bandwidth({ bps: 1024 }))
.rule(toxy.rules.method('GET'))
// Now create a route
var route = proxy.get('/foo')
// Now using the ToxyRoute interface
route
.poison(toxy.poisons.bandwidth({ bps: 512 }))
.rule(toxy.rules.contentType('json'))
A convenient wrapper internally used for poisons and rules.
Normally you don't need to know this interface, but for hacking purposes or more low-level actions might be useful.
Return: boolean
Return: boolean
Return: boolean
Alias: filter
Return: function(req, res, next)
MIT - Tomas Aparicio
FAQs
Hackable HTTP proxy to simulate server failure scenarios and network conditions
We found that toxy demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Ransomware costs victims an estimated $30 billion per year and has gotten so out of control that global support for banning payments is gaining momentum.
Application Security
New SEC disclosure rules aim to enforce timely cyber incident reporting, but fear of job loss and inadequate resources lead to significant underreporting.
Security News
The Python Software Foundation has secured a 5-year sponsorship from Fastly that supports PSF's activities and events, most notably the security and reliability of the Python Package Index (PyPI).