htaccess - redirect to URL from query string

Solution 1:

  1. my URL is not decoded

The QUERY_STRING server variable is not URL decoded, and mod_rewrite will also URL encode the substitution, so you are likely ending up with a doubly encoded URL? You probably need the NE (NOESCAPE) flag.

However, if colons and slashes (as in http://) are URL encoded (ie. http:%3A%2F%2F) in the query string parameter then these will be passed through to the substitution already encoded, negating their normal meaning in a URL. Whilst most URL encoding functions will encode these characters, they don't strictly need to be encoded in the URL parameter value (although this can depend on your server config - if you are changing what the server considers URL delimiters - but this is rare). So, encode all other characters, except : and / in the URL param value. For example, instead of:

example.com/?redirect=https%3A%2F%2Fwww.google.pl%2F

Leave the : (colon) and / (slash) chars unencoded:

example.com/?redirect=https://www.google.pl/

An alternative, instead of using a URL parameter is to use additional PATH_INFO at the end of the URL, since this should be automatically URL decoded. However, this depends on the AcceptPathInfo directive and you will also need to enable AllowEncodedSlashes (in the server config), but this comes with its own security concerns. See the Apache docs: http://httpd.apache.org/docs/current/mod/core.html#allowencodedslashes

  1. old query string is applied.

You are explicitly telling mod_rewrite to apply the original query string with the QSA (Query String Append) flag. But it will do this by default anyway. You need to explicity remove it with either the QSD (Query String Discard) flag on Apache 2.4+, or append a ? to the RewriteRule substitution.

  1. URL is started from example.com

You need to include an absolute URL (ie. complete with scheme http://) in the URL param (or explicitly hard code this in the substitution?). Note that if the colon and/or slashes in http:// are URL encoded then Apache will not see this as an absolute URL and it will be treated as relative (to the current directory) to which Apache will prefix the directory-prefix and then try to make it absolute (because of the R flag - an external redirect) by prefixing the protocol and current domain ie. http://example.com. Not only does this wholly corrupt the redirect, it will also expose your internal directory structure.

Bringing this all together, try the following:

RewriteCond %{QUERY_STRING} redirect=(.+)
RewriteRule ^ %1? [R=302,L,NE]

This is assuming that the protocol/scheme is passed in the query string parameter. eg. http://example.com/?redirect=http://www.google.pl/

A parenthesized subpattern in the RewriteRule pattern (ie. (.*)) would seem to be unnecessary here.

A word on Security

Note that allowing any absolute URL to be used as the target in a simple redirect script like this is a security risk. If hackers were to discover this then it's likely to be abused and used as part of a redirect chain directing users to download malicious software and the like.

See also:
https://webmasters.stackexchange.com/questions/99749/301-redirect-script-being-abused-for-what-purpose