{"id":22060229,"url":"https://github.com/kage/mojolicious-plugin-trustedproxy","last_synced_at":"2025-03-23T17:19:16.551Z","repository":{"id":56832749,"uuid":"188991792","full_name":"Kage/Mojolicious-Plugin-TrustedProxy","owner":"Kage","description":"Mojolicious plugin to set the remote address, connection scheme, and more from trusted upstream proxies","archived":false,"fork":false,"pushed_at":"2020-10-07T10:56:20.000Z","size":59,"stargazers_count":1,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-28T23:13:51.551Z","etag":null,"topics":["mojolicious","perl","plugin","proxy","rfc7239","trusted-proxies","x-forwarded-for","x-real-ip"],"latest_commit_sha":null,"homepage":"","language":"Perl","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Kage.png","metadata":{"files":{"readme":"README.md","changelog":"Changes","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-05-28T08:55:07.000Z","updated_at":"2020-10-07T10:56:22.000Z","dependencies_parsed_at":"2022-09-08T02:20:28.157Z","dependency_job_id":null,"html_url":"https://github.com/Kage/Mojolicious-Plugin-TrustedProxy","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kage%2FMojolicious-Plugin-TrustedProxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kage%2FMojolicious-Plugin-TrustedProxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kage%2FMojolicious-Plugin-TrustedProxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kage%2FMojolicious-Plugin-TrustedProxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Kage","download_url":"https://codeload.github.com/Kage/Mojolicious-Plugin-TrustedProxy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245136529,"owners_count":20566605,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["mojolicious","perl","plugin","proxy","rfc7239","trusted-proxies","x-forwarded-for","x-real-ip"],"created_at":"2024-11-30T17:46:44.031Z","updated_at":"2025-03-23T17:19:16.511Z","avatar_url":"https://github.com/Kage.png","language":"Perl","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/Kage/Mojolicious-Plugin-TrustedProxy.svg?branch=master)](https://travis-ci.org/Kage/Mojolicious-Plugin-TrustedProxy)\n[![Coverage Status](https://coveralls.io/repos/Kage/Mojolicious-Plugin-TrustedProxy/badge.svg?branch=master)](https://coveralls.io/r/Kage/Mojolicious-Plugin-TrustedProxy?branch=master)\n[![Kwalitee status](http://cpants.cpanauthors.org/dist/Mojolicious-Plugin-TrustedProxy.png)](http://cpants.charsbar.org/dist/overview/Mojolicious-Plugin-TrustedProxy)\n[![Cpan license](https://img.shields.io/cpan/l/Mojolicious-Plugin-TrustedProxy.svg)](https://metacpan.org/release/Mojolicious-Plugin-TrustedProxy)\n[![Cpan version](https://img.shields.io/cpan/v/Mojolicious-Plugin-TrustedProxy.svg)](https://metacpan.org/release/Mojolicious-Plugin-TrustedProxy)\n[![GitHub tag](https://img.shields.io/github/tag/Kage/Mojolicious-Plugin-TrustedProxy.svg)]()\n[![GitHub issues](https://img.shields.io/github/issues/Kage/Mojolicious-Plugin-TrustedProxy.svg)](https://github.com/Kage/Mojolicious-Plugin-TrustedProxy/issues)\n\n# NAME\n\nMojolicious::Plugin::TrustedProxy - Mojolicious plugin to set the remote\naddress, connection scheme, and more from trusted upstream proxies\n\n# VERSION\n\nVersion 0.05\n\n# SYNOPSIS\n\n    use Mojolicious::Lite;\n\n    plugin 'TrustedProxy' =\u003e {\n      enabled         =\u003e 1,\n      ip_headers      =\u003e ['x-forwarded-for', 'x-real-ip'],\n      scheme_headers  =\u003e ['x-forwarded-proto', 'x-ssl'],\n      https_values    =\u003e ['https', 'on', '1', 'true', 'enable', 'enabled'],\n      parse_rfc7239   =\u003e 1,\n      trusted_sources =\u003e ['127.0.0.0/8', '10.0.0.0/8'],\n      hide_headers    =\u003e 0,\n    };\n\n    # Example of how you could verify expected functionality\n    get '/test' =\u003e sub {\n      my $c = shift;\n      $c-\u003erender(json =\u003e {\n        'tx.remote_address'            =\u003e $c-\u003etx-\u003eremote_address,\n        'tx.remote_proxy_address'      =\u003e $c-\u003etx-\u003eremote_proxy_address,\n        'req.url.base.scheme'          =\u003e $c-\u003ereq-\u003eurl-\u003ebase-\u003escheme,\n        'req.url.base.host'            =\u003e $c-\u003ereq-\u003eurl-\u003ebase-\u003ehost,\n        'is_trusted_source'            =\u003e $c-\u003eis_trusted_source,\n        'is_trusted_source(\"1.1.1.1\")' =\u003e $c-\u003eis_trusted_source('1.1.1.1'),\n      });\n    };\n\n    app-\u003estart;\n\n# DESCRIPTION\n\n[Mojolicious::Plugin::TrustedProxy](https://metacpan.org/pod/Mojolicious::Plugin::TrustedProxy) modifies every [Mojolicious](https://metacpan.org/pod/Mojolicious) request\ntransaction to override connecting user agent values only when the request\ncomes from trusted upstream sources. You can specify multiple request headers\nwhere trusted upstream sources define the real user agent IP address or the\nreal connection scheme, or disable either, and can hide the headers from the\nrest of the application if needed.\n\nThis plugin provides much of the same functionality as setting\n`MOJO_REVERSE_PROXY=1`, but with more granular control over what headers to\nuse and what upstream sources can send them. This is especially useful if your\nMojolicious app is directly exposed to the internet, or if it sits behind\nmultiple upstream proxies. You should therefore ensure your application does\nnot enable the default Mojolicious reverse proxy handler when using this plugin.\n\nThis plugin supports parsing [RFC 7239](http://tools.ietf.org/html/rfc7239)\ncompliant `Forwarded` headers, validates all IP addresses, and will\nautomatically convert RFC-4291 IPv4-to-IPv6 mapped values (useful for when your\nMojolicious listens on both IP versions). Please be aware that `Forwarded`\nheaders are only partially supported. More information is available in [\"BUGS\"](#bugs).\n\nDebug logging can be enabled by setting the `MOJO_TRUSTEDPROXY_DEBUG`\nenvironment variable. This plugin also adds a `remote_proxy_address`\nattribute into `Mojo::Transaction`. If a remote IP address override header is\nmatched from a trusted upstream proxy, then `tx-\u003eremote_proxy_address`\nwill be set to the IP address of that proxy.\n\n# CONFIG\n\n## enabled\n\nThis allows you to load this plugin to access the [helper](#helpers) functions\nwithout automatically running the `around_dispatch` hook on each request.\nDefault is `1` (enabled).\n\n## ip\\_headers\n\nList of zero, one, or many HTTP headers where the real user agent IP address\nwill be defined by the trusted upstream sources. The first matched header is\nused. An empty value will disable this and keep the original scheme value.\nDefault is `['x-forwarded-for', 'x-real-ip']`.\n\nIf a header is matched in the request, then `tx-\u003eremote_address` is set to\nthe value, and `tx-\u003eremote_proxy_address` is set to the IP address of the\nupstream source.\n\n## scheme\\_headers\n\nList of zero, one, or many HTTP headers where the real user agent connection\nscheme will be defined by the trusted upstream sources. The first matched\nheader is used. An empty value will disable this and keep the original remote\naddress value. Default is `['x-forwarded-proto', 'x-ssl']`.\n\nThis tests that the header value is \"truthy\" but does not contain the literal\nbarewords `http`, `off`, or `false`. If the header contains any other\n\"truthy\" value, then `req-\u003eurl-\u003ebase-\u003escheme` is set to `https`.\n\n## protocol\\_headers\n\nAlias for [\"scheme\\_headers\"](#scheme_headers).\n\n## https\\_values\n\nList of values to consider as \"truthy\" when evaluating the headers in\n[\"scheme\\_headers\"](#scheme_headers). Default is\n`['https', 'on', '1', 'true', 'enable', 'enabled']`.\n\n## parse\\_rfc7239\n\nEnable support for parsing [RFC 7239](http://tools.ietf.org/html/rfc7239)\ncompliant `Forwarded` HTTP headers. Default is `1` (enabled).\n\nIf a `Forwarded` header is matched, the following actions occur with the first\nsemicolon-delimited group of parameters found in the header value:\n\n- If the `for` parameter is found, then `tx-\u003eremote_address` is set to the\nfirst matching value.\n- If the `by` parameter is found, then `tx-\u003eremote_proxy_address` is set\nto the first matching value, otherwise it is set to the IP address of the\nupstream source.\n- If the `proto` parameter is found, then `req-\u003eurl-\u003ebase-\u003escheme` is set\nto the first matching value.\n- If the `host` parameter is found, then `req-\u003eurl-\u003ebase-\u003ehost` is set to\nthe first matching value.\n\n**Note!** If enabled, the headers defined in [\"ip\\_headers\"](#ip_headers) and\n[\"scheme\\_headers\"](#scheme_headers) will be overridden by any corresponding values found in\nthe `Forwarded` header.\n\n## parse\\_forwarded\n\nAlias for [\"parse\\_rfc7239\"](#parse_rfc7239).\n\n## trusted\\_sources\n\nList of one or more IP addresses or CIDR classes that are trusted upstream\nsources. (**Warning!** An empty value will trust from all IPv4 sources!) Default\nis `['127.0.0.0/8', '10.0.0.0/8']`.\n\nSupports all IP, CIDR, and range definition types from [Net::CIDR::Lite](https://metacpan.org/pod/Net::CIDR::Lite).\n\n## hide\\_headers\n\nHide all headers defined in [\"ip\\_headers\"](#ip_headers), [\"scheme\\_headers\"](#scheme_headers), and\n`Forwarded` from the rest of the application when coming from trusted upstream\nsources. Default is `0` (disabled).\n\n# HELPERS\n\n## is\\_trusted\\_source\n\n    # From Controller context\n    sub get_page {\n      my $c = shift;\n      if ($c-\u003eis_trusted_source || $c-\u003eis_trusted_source('1.2.3.4')) {\n        ...\n      }\n    }\n\nValidate if an IP address is in the [\"trusted\\_sources\"](#trusted_sources) list. If no argument is\nprovided, then this helper will first check `tx-\u003eremote_proxy_address`\nthen `tx-\u003eremote_address`. Returns `1` if in the [\"trusted\\_sources\"](#trusted_sources)\nlist, `0` if not, or `undef` if the IP address is invalid.\n\n## process\\_ip\\_headers\n\n    # From Controller context\n    sub get_page {\n      my $c = shift;\n      my $matched_header = $c-\u003eprocess_ip_headers(1);\n    }\n\nFinds the first matching header from [\"ip\\_headers\"](#ip_headers) and sets\n`tx-\u003eremote_address` to the value (if a valid IP address), sets\n`tx-\u003eremote_proxy_address` to the IP address of the upstream proxy, and\nreturns a hash of the name and value of the matched header. Otherwise returns\n`0` if no match is found.\n\nIf any \"truthy\" value is passed as a parameter to this helper, it will first\nrun the [\"is\\_trusted\\_source\"](#is_trusted_source) helper (no arguments passed) and will return\n`undef` if it returns a false value.\n\n**WARNING!** Calling this helper when [\"enabled\"](#enabled) is set to true will likely\nproduce unexpected results.\n\n## process\\_scheme\\_headers\n\n    # From Controller context\n    sub get_page {\n      my $c = shift;\n      my $matched_header = $c-\u003eprocess_scheme_headers(1);\n    }\n\nFinds the first matching header from [\"scheme\\_headers\"](#scheme_headers) and sets\n`req-\u003eurl-\u003ebase-\u003escheme` to `https` if the header value matches any\ndefined in [\"https\\_values\"](#https_values), and returns a hash of the name and value of the\nmatched header. Otherwise returns `0` if no match is found.\n\nIf any \"truthy\" value is passed as a parameter to this helper, it will first\nrun the [\"is\\_trusted\\_source\"](#is_trusted_source) helper (no arguments passed) and will return\n`undef` if it returns a false value.\n\n**WARNING!** Calling this helper when [\"enabled\"](#enabled) is set to true will likely\nproduce unexpected results.\n\n## process\\_protocol\\_headers\n\nAlias for [\"process\\_scheme\\_headers\"](#process_scheme_headers).\n\n## process\\_rfc7239\\_header\n\n    # From Controller context\n    sub get_page {\n      my $c = shift;\n      my @matched_params = $c-\u003eprocess_rfc7239_header(1);\n    }\n\nProcess an RFC 7239 (\"Forwarded\") HTTP header if found. See [\"parse\\_rfc7239\"](#parse_rfc7239)\nfor more details. If the \"Forwarded\" header is found, this helper will return\nan array of hashes of the matched RFC 7239 parameters and values, or `0` if no\nmatches are found.\n\nIf any \"truthy\" value is passed as a parameter to this helper, it will first\nrun the [\"is\\_trusted\\_source\"](#is_trusted_source) helper (no arguments passed) and will return\n`undef` if it returns a false value.\n\n**WARNING!** Calling this helper when [\"enabled\"](#enabled) is set to true will likely\nproduce unexpected results.\n\n## process\\_forwarded\\_header\n\nAlias for [\"process\\_rfc7239\\_header\"](#process_rfc7239_header).\n\n## hide\\_upstream\\_headers\n\n    # From Controller context\n    sub get_page {\n      my $c = shift;\n      $c-\u003ehide_headers(1);\n    }\n\nRemove all headers defined in [\"ip\\_headers\"](#ip_headers), [\"scheme\\_headers\"](#scheme_headers), and\n`Forwarded` from the request.\n\nIf any \"truthy\" value is passed as a parameter to this helper, it will first\nrun the [\"is\\_trusted\\_source\"](#is_trusted_source) helper (no arguments passed) and will return\n`undef` if it returns a false value.\n\n# CDN AND CLOUD SUPPORT\n\n[Mojolicious::Plugin::TrustedProxy](https://metacpan.org/pod/Mojolicious::Plugin::TrustedProxy) is compatible with assumedly all\nthird-party content delivery networks and cloud providers. Below is an\nincomplete list of some of the most well-known providers and the recommended\n[config](#config) values to use for them.\n\n## Akamai\n\n- ip\\_headers\n\n    Set [\"ip\\_headers\"](#ip_headers) to `['true-client-ip']` (unless you set this to a different\n    value) and enable True Client IP in the origin server behavior for your site\n    property. Akamai also supports `['x-forwarded-for']`, which is enabled by\n    default in [Mojolicious::Plugin::TrustedProxy](https://metacpan.org/pod/Mojolicious::Plugin::TrustedProxy).\n\n- scheme\\_headers\n\n    There is no known way to pass this by default with Akamai. It may be possible\n    to pass a custom header via a combination of a Site Property variable and a\n    custom behavior that injects an outgoing request header based on that variable,\n    but this has not been tested or confirmed.\n\n- trusted\\_sources\n\n    This is only possible if you have the\n    [Site Shield](https://www.akamai.com/us/en/products/security/site-shield.jsp)\n    product from Akamai. If so, set [\"trusted\\_sources\"](#trusted_sources) to the complete list of\n    IPs provided in your Site Shield map.\n\n## AWS\n\n- ip\\_headers\n\n    The AWS Elastic Load Balancer uses `['x-forwarded-for']`, which is enabled by\n    default in [Mojolicious::Plugin::TrustedProxy](https://metacpan.org/pod/Mojolicious::Plugin::TrustedProxy).\n\n- scheme\\_headers\n\n    The AWS Elastic Load Balancer uses `['x-forwarded-proto']`, which is enabled\n    by default in [Mojolicious::Plugin::TrustedProxy](https://metacpan.org/pod/Mojolicious::Plugin::TrustedProxy).\n\n- trusted\\_sources\n\n    Depending on your setup, this could be one of the `172.x.x.x` IP addresses\n    or ranges within your Virtual Private Cloud, the IP address(es) of your Elastic\n    or Application Load Balancer, or could be the public IP ranges for your AWS\n    region. Go to\n    [https://docs.aws.amazon.com/general/latest/gr/aws-ip-ranges.html](https://docs.aws.amazon.com/general/latest/gr/aws-ip-ranges.html) for an\n    updated list of AWS's IPv4 and IPv6 CIDR ranges.\n\n## Cloudflare\n\n- ip\\_headers\n\n    Set [\"ip\\_headers\"](#ip_headers) to `['cf-connecting-ip']`, or `['true-client-ip']` if\n    using an enterprise plan. Cloudflare also supports `['x-forwarded-for']`,\n    which is enabled by default in [Mojolicious::Plugin::TrustedProxy](https://metacpan.org/pod/Mojolicious::Plugin::TrustedProxy).\n\n- scheme\\_headers\n\n    Cloudflare uses the `x-forwarded-proto` header, which is enabled by default\n    in [Mojolicious::Plugin::TrustedProxy](https://metacpan.org/pod/Mojolicious::Plugin::TrustedProxy).\n\n- trusted\\_sources\n\n    Go to [https://www.cloudflare.com/ips/](https://www.cloudflare.com/ips/) for an updated list of Cloudflare's\n    IPv4 and IPv6 CIDR ranges.\n\n# SECURITY\n\nCaution should be taken that you set only the [\"CONFIG\"](#config) values necessary for\nyour application in a most-common-first order, and that your upstream proxies\nremove any headers you do not want passed through to your application.\n\nFor example, if you use Cloudflare and set [\"ip\\_headers\"](#ip_headers) to\n`['x-real-ip', 'cf-connecting-ip']` and did not configure Cloudflare to\nremove `x-real-ip` headers from requests, an attacker could use this trick\nyour application into using whatever IP he or she defines due to being passed\nthrough your trusted proxy and the `x-real-ip` header being the first to be\nevaluated.\n\n# AUTHOR\n\nKage \u0026lt;kage _AT_ kage _DOT_ wtf\u003e\n\n# BUGS\n\nPlease report any bugs or feature requests on Github:\n[https://github.com/Kage/Mojolicious-Plugin-TrustedProxy](https://github.com/Kage/Mojolicious-Plugin-TrustedProxy)\n\n- Hostnames not supported\n\n    Excluding the `host` parameter of RFC 7239, this plugin does not currently\n    support hostnames or hostname resolution and there are no plans to implement\n    this. If you have a use case that requires this, please feel free to submit a\n    pull request.\n\n- HTTP 'Forwarded' only partially supported\n\n    Only partial support for RFC 7239 is currently implemented, but this should\n    work with most common use cases. The full specification allows for complex\n    structures and quoting that is difficult to implement safely. Full RFC support\n    is expected to be implemented soon.\n\n# SEE ALSO\n\n[Mojolicious::Plugin::RemoteAddr](https://metacpan.org/pod/Mojolicious::Plugin::RemoteAddr), [Mojolicious::Plugin::ClientIP::Pluggable](https://metacpan.org/pod/Mojolicious::Plugin::ClientIP::Pluggable),\n[Mojolicious](https://metacpan.org/pod/Mojolicious), [Mojolicious::Guides](https://metacpan.org/pod/Mojolicious::Guides), [http://mojolicio.us](http://mojolicio.us).\n\n# COPYRIGHT\n\nMIT License\n\nCopyright (c) 2019 Kage\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkage%2Fmojolicious-plugin-trustedproxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkage%2Fmojolicious-plugin-trustedproxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkage%2Fmojolicious-plugin-trustedproxy/lists"}