Open Redirect Security Feature
Overview
Web applications that redirect the user to another location based on user-controlled input are vulnerable to Open Redirect attacks. In such attacks, the attacker can specify a link to an external site and use that link in an HTTP redirect operation. This attack simplifies phishing attacks. Open Redirect attacks are included in the SANS Top 25 Most Dangerous Software Errors.
Open Redirect vulnerabilities are covered by CWE-601.
This rule provides protection only when user input is received via an API that is enabled in the input
declaration of the rule.
The ARMR Redirect security feature can be used to enable protection against Open Redirect attacks.
Given (Conditions)
The user can specify two conditions in the ARMR http
rule to enable the ARMR Redirect security feature - input
and response
.
input | This allows the user to specify the source of the untrusted data. The following three sources are supported:- http data introduced via HTTP/HTTPS requests |
-
database
data introduced via JDBC connections -
deserialization
data introduced via Java or XML deserializationThe rule will trigger if the source of the untrusted data matches that specified in the rule.If no value is specified then a default value ofhttp
is used.An exception will be thrown if an unsupported value is provided. | | response | This allows the user to specify that protection is required for an HTTP/HTTPS response. |
When (Event)
open-redirect | This condition allows the user to specify that protection against open redirect attacks is required.This can be declared empty, without any parameters, indicating that protection against open redirects is required for all external domains or IP addresses.Alternatively, the user may specify the following options as a parameter:- open-redirect(options: {exclude: subdomains}) This option is useful for applications that require open redirects to subdomains of the same root domain to be allowed. Specifying the exclude: subdomains option allows all HTTP server-side redirects to URLs as long as the parent subdomain or root domain is the same as the application’s domain. For example:- if the domain of the application is foo.com , then it may be necessary to allow open redirects to subdomains such as: |
-
bar.foo.com
-
example.foo.com
-
if the domain of the application is
something.foo.com
then it may be necessary to allow open redirects to another domain that has the same parent domain, such as:somethingElse.foo.com
It is also possible to specify the list of host names for which the rule applies, which is useful in cases when the application does need to allow the open-redirect to selected hosts.-open-redirect(hosts: ["www.example.com", "www.example.net"])
When the rule is defined for a single host name, the following alternative syntax is allowed:-open-redirect(hosts: "www.example.com")
|
Then (Action)
protect | Malicious open redirect operations are blocked and an HTTP error code 403 is returned to the browser.If configured, a log message is generated with details of the event. |
detect | Monitoring mode: the application behaves as normal. Malicious open redirect operations are allowed and no HTTP error is returned to the browser.If configured, a log message is generated with details of the event.A log message must be specified with this action. |
allow | Open redirect operation, to the specified host, will be allowed. |
As part of the action statement, the user may optionally specify the parameter stacktrace: “full”
. When this parameter is specified, the stacktrace of the location of the attempted exploit is included in the security log entry.
Examples
The following ARMR http
rule switches on the Open Redirect security feature to protect against unauthorized redirects that originate from an HTTP/HTTPS request. The input
declaration is omitted therefore a default of http
is used.
app("Open Redirect mod"):
requires(version: ARMR/2.7)
http("Protect against open redirect attacks"):
open-redirect()
response()
protect(message: "Protect external redirects.", severity: Very-High)
endhttp
endapp
Logging
When the above ARMR http
rule is triggered a log entry similar to the following is generated:
<9>1 2021-03-29T09:49:34.438+01:00 userX_system java 8189 - - CEF:0|ARMR:Open Redirect mod|Open Redirect mod|2.7|Protect against open redirect attacks|Execute Rule|Very-High|rt=Mar 29 2021 09:49:34.437 +0100 dvchost=userX_system procid=8189 appVersion=1 ruleType=http securityFeature=http open redirect act=protect msg=Protect external redirects. redirectLocation=http://www.waratek.com localIpAddress=0:0:0:0:0:0:0:1 localName=ip6-localhost serverName=localhost httpSessionId=5D7CE07F605C3A6ABCFDB35D065A95E5 taintSource=HTTP_SERVLET httpRequestUri=/spiracle/SendRedirect internalHttpRequestUri=/spiracle/SendRedirect httpCookies=JSESSIONID\=5D7CE07F605C3A6ABCFDB35D065A95E5 remoteIpAddress=0:0:0:0:0:0:0:1
Further Examples
The following mod is the same as the previous example, with the stacktrace also logged:
app("Open Redirect mod - with stacktrace"):
requires(version: ARMR/2.7)
http("Protect against open redirect attacks"):
open-redirect()
response()
protect(message: "Protect external redirects.", severity: Very-High, stacktrace: "full")
endhttp
endapp
Logging
When the above ARMR http
rule is triggered a log entry similar to the following is generated:
<9>1 2021-03-29T09:57:10.760+01:00 userX_system java 8189 - - CEF:0|ARMR:Open Redirect mod - with stacktrace|Open Redirect mod - with stacktrace|2.7|Protect against open redirect attacks|Execute Rule|Very-High|rt=Mar 29 2021 09:57:10.759 +0100 dvchost=userX_system procid=8189 appVersion=1 ruleType=http securityFeature=http open redirect act=protect msg=Protect external redirects. stacktrace=com.waratek.spiracle.misc.SendRedirect.executeRequest(SendRedirect.java:36)\ncom.waratek.spiracle.misc.SendRedirect.executeRequest(SendRedirect.java:28)\ncom.waratek.spiracle.misc.SendRedirect.doGet(SendRedirect.java:20)\njavax.servlet.http.HttpServlet.service(HttpServlet.java:624)\njavax.servlet.http.HttpServlet.service(HttpServlet.java:731)\nsun.reflect.GeneratedMethodAccessor39.invoke(Unknown Source)\nsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\njava.lang.reflect.Method.invoke(Method.java:498)\norg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)\norg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)\norg.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)\nsun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\nsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\nsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\njava.lang.reflect.Method.invoke(Method.java:498)\norg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)\norg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)\norg.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:218)\norg.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)\norg.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)\norg.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)\norg.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)\norg.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)\norg.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)\norg.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:442)\norg.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1082)\norg.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:623)\norg.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)\njava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\njava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\norg.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\njava.lang.Thread.run(Thread.java:748) redirectLocation=http://www.waratek.com localIpAddress=0:0:0:0:0:0:0:1 localName=ip6-localhost serverName=localhost httpSessionId=5D7CE07F605C3A6ABCFDB35D065A95E5 taintSource=HTTP_SERVLET httpRequestUri=/spiracle/SendRedirect internalHttpRequestUri=/spiracle/SendRedirect httpCookies=JSESSIONID\=5D7CE07F605C3A6ABCFDB35D065A95E5 remoteIpAddress=0:0:0:0:0:0:0:1
This is a mod that disallows redirects with except to a single host name, which is allowed:
app("Open Redirect mod - with Wikipedia allowed"):
requires(version: ARMR/2.7)
http("Protect against open redirect attacks"):
open-redirect()
response()
protect(message: "Protect external redirects.", severity: Very-High)
endhttp
http("Allow redirect to Wikipedia"):
open-redirect(hosts: "www.wikipedia.org")
response()
allow(message: "", severity: Low)
endhttp
endapp
The following mod detects open redirect attacks that originate from an HTTP/HTTPS request:
app("Open Redirect mod 2"):
requires(version: ARMR/2.7)
http("Detect malicious open redirect attacks"):
input(http)
response()
open-redirect()
detect(message: "Unauthorized external redirect detected.", severity: High)
endhttp
endapp
The following mod protects against open redirect attacks that originate from various untrusted sources. Logging is switched off by the omission of the log message parameter.
app("Open Redirect mod 3"):
requires(version: ARMR/2.7)
http("Protect against open redirect attacks"):
response()
input(deserialization, http, database)
open-redirect()
protect(severity: 10)
endhttp
endapp
The following mod protects against open redirect attacks that originate from a database source, providing the parent subdomain or root domain of the redirect URL is the different to the application’s domain.
app("Open Redirect mod 4"):
requires(version: ARMR/2.7)
http("Protect against open redirect attacks, excluding subdomains"):
response()
input(database)
open-redirect(options: {exclude: subdomains})
protect(message: "Open redirect attack blocked.", severity: Medium)
endhttp
endapp