If you don't already understand the security implications of ip firewalling please read understanding source ip based security. Your allow-list must encompass the intended client IPs as well as any intermediate reverse proxies that add themselves to the forwarded headers. This middleware supports both IPv4 and IPv6 ranges.
(require '[ring-firewall-middleware.core :as rfm])
(require '[ring.adapter.jetty :as jetty])
(defn admin-handler [request]
{:status 200 :body "Top Secret!"})
(def internal-network-only
(rfm/wrap-allow-ips admin-handler {:allow-list ["10.0.0.0/8"]}))
(jetty/run-jetty internal-network-only {:port 3000})
You can use concurrency throttling to limit the number of requests that simultaneously exercise some section of your app. This is useful if you have any endpoints that are particularly expensive and may cause instability if invoked enough.
It's a "throttle" and not a "limit" because new requests that would exceed the max-concurrency will block until an earlier request completes and then are processed (unless it takes so long that the client decides to stop waiting).
(require '[ring-firewall-middleware.core :as rfm])
(require '[ring.adapter.jetty :as jetty])
(defn expensive [request]
{:status 200 :body "crawl the entire database"})
(def controlled-chaos
(rfm/wrap-concurrency-throttle expensive {:max-concurrent 1}))
(jetty/run-jetty controlled-chaos {:port 3000})
You can use concurrency limiting to limit the number of requests that simultaneously exercise some section of your app. This is useful if you have any endpoints that are particularly expensive and may cause instability if invoked enough.
It's a "limit" and not a "throttle" because new requests that would exceed the max-concurrency receive an error response from the server and will need to be retried by the client at a later time.
(require '[ring-firewall-middleware.core :as rfm])
(require '[ring.adapter.jetty :as jetty])
(defn expensive [request]
{:status 200 :body "crawl the entire database"})
(def controlled-chaos
(rfm/wrap-concurrency-limit expensive {:max-concurrent 1}))
(jetty/run-jetty controlled-chaos {:port 3000})
You can use rate throttling to control the number of requests that exercise portions of your app over a period of time. This is useful if you have endpoints that are particularly expensive and may cause instability or unfairness to other users if invoked frequently enough.
It's a "throttle" and not a "limit" because new requests that would exceed the max-requests in a period will block until an earlier request completes and then are processed (unless it takes so long that the client decides to stop waiting).
(require '[ring-firewall-middleware.core :as rfm])
(require '[ring.adapter.jetty :as jetty])
(defn expensive [request]
{:status 200 :body "crawl the entire database"})
(def controlled-chaos
(rfm/wrap-rate-throttle expensive {:max-requests 100 :period 60000}))
(jetty/run-jetty controlled-chaos {:port 3000})
You can use rate limiting to control the number of requests that exercise portions of your app over a period of time. This is useful if you have endpoints that are particularly expensive and may cause instability or unfairness to other users if invoked frequently enough.
It's a "limit" and not a "throttle" because new requests that would exceed the max-requests in a period will receive an error response from the server and will need to be retried by the client at a later time.
(require '[ring-firewall-middleware.core :as rfm])
(require '[ring.adapter.jetty :as jetty])
(defn expensive [request]
{:status 200 :body "crawl the entire database"})
(def controlled-chaos
(rfm/wrap-rate-limit expensive {:max-requests 100 :period 60000}))
(jetty/run-jetty controlled-chaos {:port 3000})
There is a lot of misinformation on the web about the security of IP firewalling. I will attempt to provide some clarity for the typical web developer.
This firewall is filtering inside your application code which means attackers are still causing application threads to be used and some application code to be executed. It's just a mechanism to prevent calls from network locations that aren't allowed from reaching particular code within your app.
So long as you understand the above and know that you're either pulling the correct client ip from a securely managed http header (in the case of a reverse proxy) or directly from the network packet ip (no reverse proxy) then ip firewalling is a fine security mechanism for TCP protocol.
Note that the advice here applies only to HTTP over TCP. UDP is a very different story because a single malicious packet can cause application level code to execute (there is no round trip unless implemented as part of the application level communications). Even though an attacker is still unable to access the response they can do things like DDOS another service by directing all responses from the server to that other service.
Good security professionals will always recommend "defense in depth" which would suggest sensitive things should require multiple mechanisms for access, like personal authentication and not only network access. In this way, if your network is compromised you still have other protections.
I created ring-firewall-middleware because ring-ip-whitelist uses an inefficient approach of expanding cidr ranges into an in-memory set of all IPs in that range. For large subnets this can quickly grow to a large amount of memory (70+ MB).
ring-firewall-middleware simply runs a fast bit manipulation to see if the client ip lies within the cidr range. This operation takes just 1μs and a few bytes of memory regardless of the size of the cidr range.
This project is licensed under MIT license.
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close