@@ -55,8 +55,14 @@ def initialize(app)
5555 def call ( env )
5656 return @app . call ( env ) unless LogStruct . enabled?
5757
58- # Try to process the request
58+ request = ::ActionDispatch ::Request . new ( env )
59+
5960 begin
61+ # Trigger the same spoofing checks that ActionDispatch::RemoteIp performs after
62+ # it is initialized in the middleware stack. We run this manually because we
63+ # execute before that middleware and still want spoofing attacks to surface here.
64+ perform_remote_ip_check! ( request )
65+
6066 @app . call ( env )
6167 rescue ::ActionDispatch ::RemoteIp ::IpSpoofAttackError => ip_spoof_error
6268 # Create a security log for IP spoofing
@@ -65,7 +71,7 @@ def call(env)
6571 http_method : env [ "REQUEST_METHOD" ] ,
6672 user_agent : env [ "HTTP_USER_AGENT" ] ,
6773 referer : env [ "HTTP_REFERER" ] ,
68- request_id : env [ "action_dispatch .request_id" ] ,
74+ request_id : request . request_id ,
6975 message : ip_spoof_error . message ,
7076 client_ip : env [ "HTTP_CLIENT_IP" ] ,
7177 x_forwarded_for : env [ "HTTP_X_FORWARDED_FOR" ] ,
@@ -74,13 +80,7 @@ def call(env)
7480
7581 ::Rails . logger . warn ( security_log )
7682
77- # Report the error
78- context = extract_request_context ( env )
79- LogStruct . handle_exception ( ip_spoof_error , source : Source ::Security , context : context )
80-
81- # If handle_exception raised an exception then Rails will deal with it (e.g. config.exceptions_app)
82- # If we are only logging or reporting these security errors, then return a default response
83- [ FORBIDDEN_STATUS , IP_SPOOF_HEADERS , [ IP_SPOOF_HTML ] ]
83+ [ FORBIDDEN_STATUS , IP_SPOOF_HEADERS . dup , [ IP_SPOOF_HTML ] ]
8484 rescue ::ActionController ::InvalidAuthenticityToken => invalid_auth_token_error
8585 # Create a security log for CSRF error
8686 request = ::ActionDispatch ::Request . new ( env )
@@ -102,7 +102,7 @@ def call(env)
102102
103103 # If handle_exception raised an exception then Rails will deal with it (e.g. config.exceptions_app)
104104 # If we are only logging or reporting these security errors, then return a default response
105- [ FORBIDDEN_STATUS , CSRF_HEADERS , [ CSRF_HTML ] ]
105+ [ FORBIDDEN_STATUS , CSRF_HEADERS . dup , [ CSRF_HTML ] ]
106106 rescue => error
107107 # Extract request context for error reporting
108108 context = extract_request_context ( env )
@@ -119,6 +119,23 @@ def call(env)
119119
120120 private
121121
122+ sig { params ( request : ::ActionDispatch ::Request ) . void }
123+ def perform_remote_ip_check! ( request )
124+ action_dispatch_config = ::Rails . application . config . action_dispatch
125+
126+ remote_ip_middleware = ::ActionDispatch ::RemoteIp . new (
127+ -> ( _env ) { [ 200 , { } , [ ] ] } ,
128+ action_dispatch_config . ip_spoofing_check ,
129+ action_dispatch_config . trusted_proxies
130+ )
131+
132+ return unless remote_ip_middleware . check_ip
133+
134+ ::ActionDispatch ::RemoteIp ::GetIp
135+ . new ( request , remote_ip_middleware . check_ip , remote_ip_middleware . proxies )
136+ . to_s
137+ end
138+
122139 sig { params ( env : T ::Hash [ String , T . untyped ] ) . returns ( T ::Hash [ Symbol , T . untyped ] ) }
123140 def extract_request_context ( env )
124141 request = ::ActionDispatch ::Request . new ( env )
0 commit comments