WAF Egress IP Addresses
Overview
The Expedited WAF works as a reverse proxy. Visitors connect to the WAF edge network, the WAF applies your security rules, and allowed requests are then forwarded on to your Heroku application.
Because of this, every request that reaches your application is sent
by one of the WAF’s egress IP addresses, not by the visitor directly. The visitor’s original IP address is passed along in the
X-Forwarded-For header.
The IP ranges
Requests from the WAF to your application will always come from these five ranges:
192.88.134.0/23
185.93.228.0/22
66.248.200.0/22
208.109.0.0/22
2a02:fe80::/29
How often do these ranges change?
Essentially never. The list has not changed in over five years.
The ranges are fixed
These are fixed and should they ever be added to, we will notify all users within an appropriate timeframe.
Common uses
Allowing WAF traffic through application-level IP filtering
If your application filters or throttles by client IP (for example with
Rack::Attack or similar middleware), make sure these five ranges are
never blocked. The client IP your framework reports for a request
(Rack’s req.ip, Rails’
request.remote_ip) is normally a WAF address, so all
of your legitimate visitor traffic appears to come from them.
For the same reason, rate limiting should key on the visitor’s own
address, which the WAF passes in the X-Real-IP
header, rather than on that reported client IP. From your app’s point
of view, every visitor shares the same small pool of WAF addresses, so
per-IP throttles keyed on the reported client IP will lump all of your
visitors together.
Only trust X-Real-IP on requests that came through
the WAF. Anyone who reaches your Heroku app URL directly can send the
header with any value, so lock your app down to WAF traffic first (see
“Verifying that requests came through the WAF” below).
Verifying that requests came through the WAF
To accept only requests that passed through the WAF, and reject anything sent straight to your Heroku app URL, check the address that connected to Heroku against these ranges inside your application.
On the Heroku Common Runtime, the connection your dyno sees always
comes from Heroku’s router, so the socket’s source IP can’t tell you
anything. Instead, Heroku’s router appends the address that connected
to it as the last entry of the X-Forwarded-For
header. For a request through the WAF, that last entry is a WAF
address. Check that entry:
- Use the last entry, never the first. The first entry is the
visitor’s address, and anyone can put any value there by sending
their own
X-Forwarded-Forheader. - If you’ve added these ranges to Rails’
config.action_dispatch.trusted_proxies, don’t userequest.remote_ipfor this check: Rails skips trusted addresses, so it returns the visitor’s address instead of the WAF’s. - There’s no secret header the WAF can add to prove a request came through it. The IP ranges are the check.
For a Rails app, a Rack::Attack blocklist does this:
# config/initializers/rack_attack.rb
require "ipaddr"
EXPEDITED_WAF_RANGES = %w[
192.88.134.0/23 185.93.228.0/22 66.248.200.0/22 208.109.0.0/22 2a02:fe80::/29
].map { |range| IPAddr.new(range) }.freeze
Rack::Attack.blocklist("direct to origin") do |req|
next false unless Rails.env.production?
connecting_ip = req.get_header("HTTP_X_FORWARDED_FOR").to_s.split(",").last.to_s.strip
ip = (IPAddr.new(connecting_ip) rescue nil)
ip.nil? || EXPEDITED_WAF_RANGES.none? { |range| range.include?(ip) }
end
Requests sent straight to your Heroku app URL then get a 403. The
check runs only in production: in local development there’s no
X-Forwarded-For header, so every request would be
blocked. Webhooks and other services that call your
herokuapp.com URL directly, rather than your custom
domain, are blocked too, so point them at your custom domain first.
The same check works in any framework: split the header on commas,
take the last entry, and compare it to the five ranges.
Heroku Private Space customers can enforce this at the network level instead, so that direct-to-app requests are rejected before they reach a dyno. See the article “Heroku Private Space Trusted IP Range Configuration” for that setup.
What these ranges are not
These are the addresses the WAF connects from when forwarding visitor requests to your application. They are unrelated to outbound requests your application makes to other services, which leave directly from your Heroku dyno and never pass through the WAF. See “WAF and Outbound Connections” for more detail.
Need Help?
- Contact us at support@expeditedsecurity.com
- Book a Call at https://app.harmonizely.com/expedited/30-min