Merge branch 'main' into Xe/double-slash-try-3

Signed-off-by: Xe Iaso <xe.iaso@techaro.lol>
This commit is contained in:
Xe Iaso
2025-09-25 04:52:29 -04:00
committed by GitHub
6 changed files with 42 additions and 14 deletions

View File

@@ -68,7 +68,7 @@ var (
slogLevel = flag.String("slog-level", "INFO", "logging level (see https://pkg.go.dev/log/slog#hdr-Levels)")
stripBasePrefix = flag.Bool("strip-base-prefix", false, "if true, strips the base prefix from requests forwarded to the target server")
target = flag.String("target", "http://localhost:3923", "target to reverse proxy to, set to an empty string to disable proxying when only using auth request")
targetSNI = flag.String("target-sni", "", "if set, the value of the TLS handshake hostname when forwarding requests to the target")
targetSNI = flag.String("target-sni", "", "if set, TLS handshake hostname when forwarding requests to the target, if set to auto, use Host header")
targetHost = flag.String("target-host", "", "if set, the value of the Host header when forwarding requests to the target")
targetInsecureSkipVerify = flag.Bool("target-insecure-skip-verify", false, "if true, skips TLS validation for the backend")
targetDisableKeepAlive = flag.Bool("target-disable-keepalive", false, "if true, disables HTTP keep-alive for the backend")
@@ -83,6 +83,7 @@ var (
versionFlag = flag.Bool("version", false, "print Anubis version")
publicUrl = flag.String("public-url", "", "the externally accessible URL for this Anubis instance, used for constructing redirect URLs (e.g., for forwardAuth).")
xffStripPrivate = flag.Bool("xff-strip-private", true, "if set, strip private addresses from X-Forwarded-For")
customRealIPHeader = flag.String("custom-real-ip-header", "", "if set, read remote IP from header of this name (in case your environment doesn't set X-Real-IP header)")
thothInsecure = flag.Bool("thoth-insecure", false, "if set, connect to Thoth over plain HTTP/2, don't enable this unless support told you to")
thothURL = flag.String("thoth-url", "", "if set, URL for Thoth, the IP reputation database for Anubis")
@@ -235,23 +236,28 @@ func makeReverseProxy(target string, targetSNI string, targetHost string, insecu
if insecureSkipVerify || targetSNI != "" {
transport.TLSClientConfig = &tls.Config{}
if insecureSkipVerify {
slog.Warn("TARGET_INSECURE_SKIP_VERIFY is set to true, TLS certificate validation will not be performed", "target", target)
transport.TLSClientConfig.InsecureSkipVerify = true
}
if targetSNI != "" {
transport.TLSClientConfig.ServerName = targetSNI
}
}
if insecureSkipVerify {
slog.Warn("TARGET_INSECURE_SKIP_VERIFY is set to true, TLS certificate validation will not be performed", "target", target)
transport.TLSClientConfig.InsecureSkipVerify = true
}
if targetSNI != "" && targetSNI != "auto" {
transport.TLSClientConfig.ServerName = targetSNI
}
rp := httputil.NewSingleHostReverseProxy(targetUri)
rp.Transport = transport
if targetHost != "" {
if targetHost != "" || targetSNI == "auto" {
originalDirector := rp.Director
rp.Director = func(req *http.Request) {
originalDirector(req)
req.Host = targetHost
if targetHost != "" {
req.Host = targetHost
}
if targetSNI == "auto" {
transport.TLSClientConfig.ServerName = req.Host
}
}
}
@@ -460,6 +466,7 @@ func main() {
var h http.Handler
h = s
h = internal.CustomRealIPHeader(*customRealIPHeader, h)
h = internal.RemoteXRealIP(*useRemoteAddress, *bindNetwork, h)
h = internal.XForwardedForToXRealIP(h)
h = internal.XForwardedForUpdate(*xffStripPrivate, h)

View File

@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
<!-- This changes the project to: -->
- Add `-custom-real-ip-header` flag to get the original request IP from a different header than `x-real-ip`.
- Add `contentLength` variable to bot expressions.
- Add `COOKIE_SAME_SITE_MODE` to force anubis cookies SameSite value, and downgrade automatically from `None` to `Lax` if cookie is insecure.
- Fix lock convoy problem in decaymap ([#1103](https://github.com/TecharoHQ/anubis/issues/1103)).
@@ -29,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Randomly use the Refresh header instead of the meta refresh tag in the metarefresh challenge.
- Update OpenRC service to truncate the runtime directory before starting Anubis.
- Allow multiple consecutive slashes in a row in application paths ([#754](https://github.com/TecharoHQ/anubis/issues/754)).
- Add option to set `targetSNI` to special keyword 'auto' to indicate that it should be automatically set to the request Host name ([424](https://github.com/TecharoHQ/anubis/issues/424)).
### Bug Fixes

View File

@@ -20,6 +20,8 @@ Upstream: X-Forwarded-For: CF_IP
As a workaround, you should configure your web server to parse an alternative source (such as `CF-Connecting-IP`), or pre-process the incoming `X-Forwarded-For` with your web server to ensure it only contains the real client IP address, then pass it to Anubis as `X-Forwarded-For`.
If you do not control the web server upstream of Anubis, the `custom-real-ip-header` command line flag accepts a header value that Anubis will read the real client IP address from. Anubis will set the `X-Real-IP` header to the IP address found in the custom header.
The `X-Real-IP` header will be automatically inferred from `X-Forwarded-For` if not set, setting it explicitly is not necessary as long as `X-Forwarded-For` contains only the real client IP. However setting it explicitly can eliminate spoofed values if your web server doesn't set this.
See [Cloudflare](environments/cloudflare.mdx) for an example configuration.

View File

@@ -76,6 +76,7 @@ Anubis uses these environment variables for configuration:
| `COOKIE_DOMAIN` | unset | The domain the Anubis challenge pass cookie should be set to. This should be set to the domain you bought from your registrar (EG: `techaro.lol` if your webapp is running on `anubis.techaro.lol`). See this [stackoverflow explanation of cookies](https://stackoverflow.com/a/1063760) for more information.<br/><br/>Note that unlike `REDIRECT_DOMAINS`, you should never include a port number in this variable. |
| `COOKIE_DYNAMIC_DOMAIN` | false | If set to true, automatically set cookie domain fields based on the hostname of the request. EG: if you are making a request to `anubis.techaro.lol`, the Anubis cookie will be valid for any subdomain of `techaro.lol`. |
| `COOKIE_EXPIRATION_TIME` | `168h` | The amount of time the authorization cookie is valid for. |
| `CUSTOM_REAL_IP_HEADER` | unset | If set, Anubis will read the client's real IP address from this header, and set it in `X-Real-IP` header. |
| `COOKIE_PARTITIONED` | `false` | If set to `true`, enables the [partitioned (CHIPS) flag](https://developers.google.com/privacy-sandbox/cookies/chips), meaning that Anubis inside an iframe has a different set of cookies than the domain hosting the iframe. |
| `COOKIE_PREFIX` | `anubis-cookie` | The prefix used for browser cookies created by Anubis. Useful for customization or avoiding conflicts with other applications. |
| `COOKIE_SECURE` | `true` | If set to `true`, enables the [Secure flag](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Cookies#block_access_to_your_cookies), meaning that the cookies will only be transmitted over HTTPS. If Anubis is used in an unsecure context (plain HTTP), this will be need to be set to false |
@@ -122,7 +123,7 @@ If you don't know or understand what these settings mean, ignore them. These are
| `TARGET_DISABLE_KEEPALIVE` | `false` | If `true`, disables HTTP keep-alive for connections to the target backend. Useful for backends that don't handle keep-alive properly. |
| `TARGET_HOST` | unset | If set, overrides the Host header in requests forwarded to `TARGET`. |
| `TARGET_INSECURE_SKIP_VERIFY` | `false` | If `true`, skip TLS certificate validation for targets that listen over `https`. If your backend does not listen over `https`, ignore this setting. |
| `TARGET_SNI` | unset | If set, overrides the TLS handshake hostname in requests forwarded to `TARGET`. |
| `TARGET_SNI` | unset | If set, TLS handshake hostname when forwarding requests to the `TARGET`. If set to auto, use Host header. |
</details>

View File

@@ -38,6 +38,22 @@ func UnchangingCache(next http.Handler) http.Handler {
})
}
// CustomXRealIPHeader sets the X-Real-IP header to the value of a
// different header.
// Used in environments where the upstream proxy sets the request's
// origin IP in a custom header.
func CustomRealIPHeader(customRealIPHeaderValue string, next http.Handler) http.Handler {
if customRealIPHeaderValue == "" {
slog.Debug("skipping middleware, customRealIPHeaderValue is empty")
return next
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
r.Header.Set("X-Real-IP", r.Header.Get(customRealIPHeaderValue))
next.ServeHTTP(w, r)
})
}
// RemoteXRealIP sets the X-Real-Ip header to the request's real IP if
// the setting is enabled by the user.
func RemoteXRealIP(useRemoteAddress bool, bindNetwork string, next http.Handler) http.Handler {

View File

@@ -13,7 +13,7 @@
"try_again": "Prøv att",
"go_home": "Gå heim",
"contact_webmaster": "eller om du synest at du ikkje burde vera blokkert, venlegast tak kontakt med administratoren på",
"connection_security": "Venlegast vent medan vi stadfestar tryggleiken av tilkoplinga di.",
"connection_security": "Venlegast vent medan vi stadfester tryggleiken av tilkoplinga di.",
"javascript_required": "Du lyt diverre slå på JavaScript for å koma deg forbi denne utfordringa. Dette krevst av di KI-selskap har endra sosialkontrakten om korleis nettstadsverting fungerer. Ei ikkje-JS-løysing er i gang med å skapast.",
"benchmark_requires_js": "JavaScript må vera slegen på for å køyre samanlikningsverktøyet.",
"difficulty": "Vanskenivå:",
@@ -41,7 +41,7 @@
"oh_noes": "Å nei!",
"benchmarking_anubis": "Samanliknar Anubis!",
"you_are_not_a_bot": "Du er ikkje ein bot!",
"making_sure_not_bot": "Stadfestar at du ikkje er ein bot!",
"making_sure_not_bot": "Stadfester at du ikkje er ein bot!",
"celphase": "CELPHASE",
"js_web_crypto_error": "Nettlesaren din har ikkje eit fungerande web.crypto-element. Ser du dette med ei sikker tilkopling?",
"js_web_workers_error": "Nettlesaren din støttar ikkje nettarbeidarar (Anubis brukar dette for å unngå å fryse nettlesaren din). Har du eit tillegg som JShelter installert?",
@@ -63,4 +63,4 @@
"js_calculation_error_msg": "Mislukkast i å rekne utfordring:",
"missing_required_forwarded_headers": "Manglende nødvendige X-Forwarded-* headers",
"simplified_explanation": "Dette er eit tiltak mot robotar og vondsinna førespurnader som liknar på ein CAPTCHA. Men i staden for å måtte gjere arbeidet sjølv, får nettlesaren din ei utrekningsoppgåve som han må løyse for å sikre at han er ein gyldig klient. Dette konseptet blir kalla <a href=\"https://en.wikipedia.org/wiki/Proof_of_work\">Arbeidsbevis</a>. Oppgåva blir rekna ut på nokre få sekund, og du får tilgang til nettstaden. Takk for di forståing og tålmod."
}
}