|
| 1 | += client-ip |
| 2 | + |
| 3 | +A 0-dependency ring middleware for determining a request's real client IP address from HTTP headers |
| 4 | + |
| 5 | +image:https://github.com/outskirtslabs/client-ip/actions/workflows/ci.yml/badge.svg[Build Status,link=https://github.com/outskirtslabs/client-ip/actions] |
| 6 | +image:https://cljdoc.org/badge/com.outskirtslabs/client-ip[cljdoc,link=https://cljdoc.org/d/com.outskirtslabs/client-ip] |
| 7 | +image:https://img.shields.io/clojars/v/com.outskirtslabs/client-ip.svg[Clojars Project,link=https://clojars.org/com.outskirtslabs/client-ip] |
| 8 | + |
| 9 | +`X-Forwarded-For` and other client IP headers are https://adam-p.ca/blog/2022/03/x-forwarded-for/[often used incorrectly], resulting in bugs and security vulnerabilities. This library provides strategies for extracting the correct client IP based on your network configuration. |
| 10 | + |
| 11 | +It is based on the golang reference implementation https://github.com/realclientip/realclientip-go[realclientip/realclientip-go]. |
| 12 | + |
| 13 | +Quick feature list: |
| 14 | + |
| 15 | +* ring middleware determining the client's IP address |
| 16 | +* 0 dependency IP address string parsing with guaranteed no trips to the hosts' DNS services, which can block and timeout (unlike Java's `InetAddress/getByName`) |
| 17 | +* rightmost-ish strategies support the `X-Forwarded-For` and `Forwarded` (RFC 7239) headers |
| 18 | +* IPv6 zone identifiers support |
| 19 | +
|
| 20 | +Note that there is no dependency on ring, the public API could also be used for pedestal or sieppari-style interceptors. |
| 21 | + |
| 22 | +== Installation |
| 23 | + |
| 24 | +[source,clojure] |
| 25 | +---- |
| 26 | +;; deps.edn |
| 27 | +{:deps {com.outskirtslabs/client-ip {:mvn/version "0.1.1"}}} |
| 28 | +
|
| 29 | +;; Leiningen |
| 30 | +[com.outskirtslabs/client-ip "0.1.1"] |
| 31 | +---- |
| 32 | + |
| 33 | +== Quick Start |
| 34 | + |
| 35 | +[source,clojure] |
| 36 | +---- |
| 37 | +(ns myapp.core |
| 38 | + (:require [ol.client-ip.core :as client-ip] |
| 39 | + [ol.client-ip.strategy :as strategy])) |
| 40 | +
|
| 41 | +;; Simple case: behind a trusted proxy that sets X-Real-IP |
| 42 | +(def app |
| 43 | + (-> handler |
| 44 | + (client-ip/wrap-client-ip |
| 45 | + {:strategy (strategy/single-ip-header-strategy "x-real-ip")}))) |
| 46 | +
|
| 47 | +;; The client IP is now available in the request |
| 48 | +(defn handler [request] |
| 49 | + (let [client-ip (:ol/client-ip request)] |
| 50 | + {:status 200 |
| 51 | + :body (str "Your IP is: " client-ip)})) |
| 52 | +---- |
| 53 | + |
| 54 | +For detailed guidance on choosing strategies, see link:doc/modules/ROOT/pages/usage.adoc[Usage Guide]. |
| 55 | + |
| 56 | +Choosing the wrong strategy can result in IP address spoofing security vulnerabilities. |
| 57 | + |
| 58 | +== Recommended Reading |
| 59 | + |
| 60 | +You think it is an easy question: |
| 61 | + |
| 62 | +____ |
| 63 | +I have an HTTP application, I just want to know the IP address of my client. |
| 64 | +____ |
| 65 | + |
| 66 | +But who is the client? |
| 67 | + |
| 68 | +____ |
| 69 | +The computer on the other end of the network connection? |
| 70 | +____ |
| 71 | + |
| 72 | +But which network connection? The one connected to your HTTP application is probably a reverse proxy or load balancer. |
| 73 | + |
| 74 | +____ |
| 75 | +Well I mean the "user's IP address" |
| 76 | +____ |
| 77 | + |
| 78 | +It ain't so easy kid. |
| 79 | + |
| 80 | +There are many good articles on the internet that discuss the perils and pitfalls of trying to answer this deceptively simple question. |
| 81 | + |
| 82 | +You _should_ read one or two of them to get an idea of the complexity in this space. Libraries, like this one, _cannot_ hide the complexity from you, there is no abstraction nor encapsulation nor "default best practice". |
| 83 | + |
| 84 | +Below are some of those good articles: |
| 85 | + |
| 86 | +* MDN: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For#security_and_privacy_concerns[X-Forwarded-For: Security and privacy concerns] |
| 87 | +* https://adam-p.ca/blog/2022/03/x-forwarded-for/[The perils of the "real" client IP] (https://web.archive.org/web/20250416042714/https://adam-p.ca/blog/2022/03/x-forwarded-for/[archive link]) |
| 88 | +* https://www.gingerlime.com/2012/rails-ip-spoofing-vulnerabilities-and-protection/[Rails IP Spoofing Vulnerabilities and Protection] (https://web.archive.org/web/20250421121810/https://www.gingerlime.com/2012/rails-ip-spoofing-vulnerabilities-and-protection/[archive link]) |
| 89 | +* https://casey.link/blog/client-ip-ring-middleware/[ol.client-ip: A Clojure Library to Prevent IP Spoofing] |
| 90 | + |
| 91 | +== Security |
| 92 | + |
| 93 | +See https://github.com/outskirtslabs/client-ip/security/advisories[here] for security advisories or to report a security vulnerability. |
| 94 | + |
| 95 | +== License |
| 96 | + |
| 97 | +Copyright (C) 2025 Casey Link <casey@outskirtslabs.com> |
| 98 | + |
| 99 | +Distributed under the https://github.com/outskirtslabs/client-ip/blob/main/LICENSE[MIT License]. |
0 commit comments