All Projects → defense-cr → defense

defense-cr / defense

Licence: other
🔮 A Crystal HTTP handler for throttling, blocking and tracking malicious requests.

Programming Languages

crystal
512 projects

Projects that are alternatives of or similar to defense

asyncio-throttle
Simple, easy-to-use throttler for asyncio.
Stars: ✭ 95 (+86.27%)
Mutual labels:  throttle, throttling
Xcrash
🔥 xCrash provides the Android app with the ability to capture java crash, native crash and ANR. No root permission or any system permissions are required.
Stars: ✭ 148 (+190.2%)
Mutual labels:  block, handler
Bblocationmanager
A Location Manager for easily implementing location services & geofencing in iOS. Ready for iOS 11.
Stars: ✭ 107 (+109.8%)
Mutual labels:  block
unicode-blocks
Unicode Blocks of a Ruby String
Stars: ✭ 18 (-64.71%)
Mutual labels:  block
Kommander Ios
A lightweight, pure-Swift library for manage the task execution in different threads. Through the definition a simple but powerful concept, Kommand.
Stars: ✭ 167 (+227.45%)
Mutual labels:  block
Readyforbat
慕课网iOS面试实战项目总结:iOS面试题思维导图与回答
Stars: ✭ 1,569 (+2976.47%)
Mutual labels:  block
Flutter colorpicker
A HSV(HSB)/HSL color picker inspired by chrome devtools and a material color picker for your flutter app.
Stars: ✭ 185 (+262.75%)
Mutual labels:  block
Coinhive Block
To block the malware domains of coin-hive systemwide.
Stars: ✭ 85 (+66.67%)
Mutual labels:  block
DebounceMonitoring
📑 Add debounce logic for any method in a single line.
Stars: ✭ 44 (-13.73%)
Mutual labels:  throttle
Bitcoin Transaction Explorer
Simple and pure block explorer you can run on top of a full node
Stars: ✭ 165 (+223.53%)
Mutual labels:  block
server init harden
Server hardening on 1st login as "root"
Stars: ✭ 75 (+47.06%)
Mutual labels:  fail2ban
Afwall
AFWall+ (Android Firewall +) - iptables based firewall for Android
Stars: ✭ 2,024 (+3868.63%)
Mutual labels:  block
Ttv aderaser
TTV AdEraser aims to remove livestream ads as well as add some useful features to our favourite streaming site.
Stars: ✭ 122 (+139.22%)
Mutual labels:  block
Blockchain Python
A blockchain implementation in Python
Stars: ✭ 233 (+356.86%)
Mutual labels:  block
Anti Webminer
Anti-WebMiner protects your PC against web cryptocurrency miners (JS scripts like Coinhive executed in the browser) by modifying Windows hosts file
Stars: ✭ 114 (+123.53%)
Mutual labels:  block
instagram-widget-by-wpzoom
The easiest way to add a nice Instagram widget on your WordPress site. It just works!
Stars: ✭ 22 (-56.86%)
Mutual labels:  block
Dotcoin
A simple and integrity blockchain implementation in Golang
Stars: ✭ 89 (+74.51%)
Mutual labels:  block
Whitepaper
免费分享区块链白皮书,涉及各门各派。内容均来自互联网,如果侵权,请联系删除。 区块链白皮书 weixin:mipengchong
Stars: ✭ 175 (+243.14%)
Mutual labels:  block
BlockHashLoc
Recover files using lists of blocks hashes, bypassing the File System entirely
Stars: ✭ 45 (-11.76%)
Mutual labels:  block
HandlerFrame
🐮 HandlerFrame是一个基于观察者模式采用信息分发机制实现跨界面Handler通讯框架,整个项目里面只存在一个Handler实例对象。
Stars: ✭ 42 (-17.65%)
Mutual labels:  handler

Defense

Build Status

🔮 A Crystal HTTP handler for throttling, blocking and tracking malicious requests 🔮

Getting started

Installation

Add the shard as a dependency to your project's shards.yml:

dependencies:
  defense:
    github: defense-cr/defense

...and install it:

shards install

Configure the data store

Defense stores its state in a Redis database. You can configure this by setting the REDIS_URL environment variable or by using the Defense#store= method:

Defense.store = Defense::RedisStore.new(url: "redis://localhost:6379/0")

For simple use cases or tests you can also use the memory store:

Defense.store = Defense::MemoryStore.new

You can always implement your own custom store by extending the abstract class Defense::Store.

Plugging into the application

Defense is built as a Crystal HTTP::Handler. You will need to register the Defense::Handler to your web application's handler chain. For more information about handlers and the handler chain follow this link.

Usually the earlier you register the handler to your handler chain, the better. This ensures that malicious requests are blocked early own, before other layers (handlers) of your application are reached.

Here's how to plug Defense into some of the most popular Crystal web frameworks:

Kemal

In Kemal you would use the add_handler method to register the Defense handler:

require "kemal"
require "defense"

add_handler Defense::Handler.new

# Other handlers...
add_handler SomeOtherHandler.new

get "/" do
  "hello world"
end

Kemal.run

For more details, check out the kemal-defense-example repository.

Amber

In Amber you register handlers as part of a pipeline in your config/routes.cr file:

Amber::Server.configure do |app|
  pipeline :web do
    plug Defense::Handler.new

    # Other handlers...
    plug SomeOtherHandler.new
  end

  routes :web do
    get "/", HomeController, :index
  end
end

Lucky

In Lucky, you would add the Defense::Handler within your src/app_server.cr file, somewhere before the Lucky::RouteHandler:

class AppServer < Lucky::BaseAppServer
  def middleware
    [
      Defense::Handler.new,

      # Other handlers...
      SomeOtherHandler.new,

      Lucky::RouteHandler.new,
    ]
  end
end

HTTP::Server (Standalone)

When using the standard library HTTP::Server, any middleware is registered as part of the initializer:

require "defense"
require "http/server"

server = HTTP::Server.new([Defense::Handler.new]) do |context|
  context.response.content_type = "text/plain"
  context.response.print "hello world"
end

server.bind_tcp(8080)
server.listen

Usage

Defense provides a set of configurable rules that you can use to throttle, block and track malicious requests based on your own heuristics:

Throttling

The Defense.throttle method can be used to throttle clients based on a maximum number of requests (limit) over a given time frame specified in seconds (period).

The method takes a block which receives the request as an argument. The return value of the block should either be nil (in which case the request will not be counted at all) or a String which uniquely identifies the client to throttle. A good identifier is usually the IP address.

The following example throttles clients based on their IP address to a limit of 10 requests per minute:

Defense.throttle("throttle requests per minute", limit: 10, period: 60) do |request|
  request.remote_address.to_s
end

The following example throttles clients in a similar way but will ignore requests coming from 127.0.0.1:

Defense.throttle("throttle requests per minute except localhost", limit: 10, period: 60) do |request|
  return nil if request.remote_address.to_s == "127.0.0.1"

  request.remote_address.to_s
end

Configure the throttled response

Throttled requests are responded with:

HTTP/1.1 429 Too Many Requests
content-type: text/plain
content-length: 10

Retry later

You can override the default response message by using the Defense.throttled_response= method:

Defense.throttled_response = ->(response : HTTP::Server::Response) do
  response.status = HTTP::Status::UNAUTHORIZED
  response.content_type = "application/json"
  response.puts("{'hello':'world'}")
end

Blocklist

The Defense.blocklist method can be used to block malicious or unwanted requests.

The method takes a block which receives the request as an argument. The return value of the block should either be true - in which case the request will be blocked, or false - in which case the request will be allowed.

The following example blocks all requests to /admin/*:

Defense.blocklist("block requests to the admin") do |request|
  request.path.starts_with?("/admin/")
end

The following example blocks requests based on a predefined list of malicious IPs:

MALICIOUS_IPS = ["1.1.1.1", "2.2.2.2", "3.3.3.3"]

Defense.blocklist("block requests from malicious ips") do |request|
  MALICIOUS_IPS.includes?(request.remote_address.to_s)
end

The Spamhaus DROP lists are a great resource for malicious IPs to block.

Configure the blocked response

Blocked requests are responded with:

HTTP/1.1 403 Forbidden
content-type: text/plain
content-length: 9

Forbidden

You can override the default response message by using the Defense.blocked_response= method:

Defense.blocked_response = ->(response : HTTP::Server::Response) do
  response.status = HTTP::Status::UNAUTHORIZED
  response.content_type = "application/json"
  response.puts("{'hello':'world'}")
end

Fail2Ban

The Defense::Fail2Ban.filter method can be used within a Defense.blocklist block to ban misbehaving clients for a given period of time (bantime) after a sequence of blocked requests (maxretry) performed over a particular time range (findtime).

The method's first argument should be a unique identifier of the client - the IP address is usually a safe bet. It's highly recommended to namespace this identifier, in order to avoid conflicts with other Fail2Ban or Allow2Ban calls - e.g. my-fancy-filter:#{request.remote_address.to_s} would be a good identifier.

The method also takes a block which should return true - in which case the request will be blocked and counted for the ban, or false - in which case the request will be allowed and excluded from the ban count. Note that the return value of the #filter block will also be used as a return value for the #blocklist block.

The following example blocks any requests containing /etc/passwd inside the path and, once a particular client identified by IP has accumulated 5 requests wihin 60 seconds, it bans him for the next 24 hours:

Defense.blocklist("fail2ban pentesters") do |request|
  Defense::Fail2Ban.filter("pentesters:#{request.remote_address.to_s}", maxretry: 5, findtime: 60, bantime: 24 * 60 * 60) do
    request.path.includes?("/etc/passwd")
  end
end

Allow2Ban

The Defense::Allow2Ban.filter method works the same way as Defense::Fail2Ban.filter except that it allows requests from misbehaving clients until such time as they reach maxretry at which they are cut off as per normal.

The following example allows all POST /login requests until a particular client identified by IP has accumulated 5 requests within 60 seconds, at which point it bans him for the next 24 hours:

Defense.blocklist("allow2ban too many login attempts") do |request|
  Defense::Allow2Ban.filter("too-many-login-attempts:#{request.remote_address.to_s}", maxretry: 5, findtime: 60, bantime: 24 * 60 * 60) do
    request.method == "POST" && request.path == "/login"
  end
end

Safelist

The Defense.safelist method can be used to exclude requests from any throttling or blocking rules. This method has precedence over all the other rules.

The method takes a block which receives the request as an argument. The return value of the block should either be true - in which case the request will never be throttled or blocked, or false - in which case the request will be checked against the other existing rules and might potentially be throttled or blocked.

The following example marks all requests originating from 127.0.0.1 as safe:

Defense.safelist("local requests are safe") do |request|
  request.remote_address.to_s == "127.0.0.1"
end

Contributing & Development

Contributions are welcome. Make sure to check the existing issues (including the closed ones) before requesting a feature, reporting a bug or opening a pull requests.

Getting started

Install dependencies:

shards install

Run tests using Redis as a backend (requires a running Redis server):

crystal spec

Run tests using the memory store as a backend:

STORE=memory crystal spec

Format the code:

crystal tool format

Guidelines

  • Keep the public interface small. Anything that doesn't have to be public, should explicitly be marked as protected or private, including classes.
  • Be explicit about type declaration (especially on public methods).
  • Use the Crystal formatter to format the code.
  • For now, prefer integration/system tests over unit tests.

Maintainers

Credits

This shard is heavily inspired by rack-attack

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].