nginx + SslRequirement + mongrel cluster = infinite redirect loop - ssl

I'm getting an infinite redirect loop after adding SSL support to my site. I'm using the "SslRequirement" plugin.
The symptoms I'm seeing are, any action that has "ssl_required" enabled, and any URL I type in manually that has https at the front, goes into an infinite loop, with the following in the development.log file, over and over until the browser catches the redirect loop and stops the loading of the page ("/admins/index" is the action in this example, but it happens with any action):
Processing AdminsController#index (for 127.0.0.1 at 2010-08-13 13:50:16) [GET]
Parameters: {"action"=>"index", "controller"=>"admins"}
Redirected to https://localhost/admins
Filter chain halted as [:ensure_proper_protocol] rendered_or_redirected.
Completed in 0ms (DB: 0) | 302 Found [http://localhost/admins]
At first I thought there was some kind of problem where I had to make ALL of my actions "ssl_allowed" - so I tried that, but to no avail.
IF I remove the use of SslRequirement, and remove any "ssl_required/ssl_allowed" references, then https works fine - so it's the redirect in actions from http to https that seems to be the issue.
Any clues?

Answer found here:
http://www.hostingrails.com/SSL-Redirecting-not-working
Short version is, I added the following line to the SSL vhost in my nginx config:
proxy_set_header X_FORWARDED_PROTO https;
Detailed version is:
Basically the issue came down to the nginx server not passing the fact that the source request was an HTTPS protocol on to the Mongrel cluster. This caused the call to "request.ssl?" inside the SslRequirement plugin to ALWAYS return false.
So, when this returned as false, the "ensure_proper_protocol" would re-issue the action over https, which would check "request.ssl?", which would return "false", which would re-issue the action over https, which would check "request.ssl?", which would return "false", which would re-issue the action over https, which would check "request.ssl?", which would return "false", which would re-issue the action over https, which would check "request.ssl?", which would return "false", which would re-issue the action over https ...
...you get the idea. The mongrel cluster NEVER thought the request was over the HTTPS protocol, so it redirected forever. A small change in the nginx config to correct this, and BAM-O: problem solved.

Related

CloudFlare workers fetch HTTPS works on workers.dev subdomain but not on own subdomain getting 525 error

I have a simple worker that just does a fetch against an HTTPS endpoint somewhere else.
The code is literally just:
return await fetch('https://something.com/someResource')
When I test locally (wrangler dev) and even publish to a workers subdomain this works fine. When I curl https://foo.bar.workers.dev/myEndpoint I get the same response as https://something.com/someResource.
However I want to run this from my own domain (managed through cloudflare) so the worker also has a route of foo.mydomain.com/* and a AAAA record to 100:: for foo as per CloudFlare docs. The DNS works fine the URL is reachable, but when I try to hit https://foo.mydomain.com/myEndpoint CloudFlare's worker logs show that the fetch behind the scenes fails with a 525 error (SSL Handshake fail).
Things I've tried based on some CloudFlare forum posts:
Add a page rule foo.mydomain.com/* -> SSL Mode: full since my overall SSL settings are set to flexible.
Set the host header in the fetch to the origin domain ( fetch(url, {headers: {'Host': 'something.com'}})
FYI, I don't control the origin server as it's an external API I work with.
How come the same request works from local and *.workers.dev but not my own domain?
Your page rule is not taking effect. The page rule is for foo.mydomain.com/*, but it has to match the subrequest URL, which in this case is https://something.com/someResource, which doesn't match. It doesn't matter that the original worker request matched -- what matters, in this case, is whether the subrequest URL matched.
Unfortunately, you cannot create a page rule that matches a domain other than your own.
Instead, what you'll need to do is reverse things. Set your SSL mode to "full" by default, but then use page rules to set it to "flexible" for your own domain.
(Note: The "SSL Handshake fail" error itself is actually a known bug in Workers, that happens when you try to talk to a host outside your zone using HTTPS but you have "flexbile" SSL set. We do not use flexible SSL when talking to domains other than your own, but there's a bug that causes the request to fail instead of just using full SSL as it should.)

force_ssl even behind nginx and generate https url

I'm trying to get force_ssl working. I mean I want to redirect someone trying to connect via http to https with the app itself.
The app is a dockerized released version behind Nginx. Actually Nginx is serving the SSL and I know that I can totally rely on Nginx to terminate the ssl connection and even taking care of the redirection of non https requests. But I want to understand how to make it work so if someday I skip the proxy I'll know how to do it.
My prod/config looks like that:
config :my_app, MyApp.Endpoint,
http: [port: "${PORT}"],
url: [host: "${APP_URL}", port: "${APP_PORT}"],
force_ssl: [hsts: true], #I tried different options without success
server: true,
cache_static_manifest: "priv/static/manifest.json",
root: ".",
version: Mix.Project.config[:version]
Actually when accessing the server via https everything runs as expected. But when using http address, the redirect url looks like: https://%24%7Bapp_url%7D/ and it didn't work.
Maybe this happens because I didn't give a cert file and the whole process cannot be done without it? I was thinking that force_ssl is just a basic redirection if the request isn't https.
Finally I'm also trying to generate https url for instance in a mailer I've got something like this:
<%= password_url(MyApp.Endpoint, :reset_password_from_email, token: #token, email: #email) %>
But since my configuration seems not good it only generate http links not https.
Maybe should I separate this completely, making this 100% on Nginx side or 100% on the app side but not trying to mix them both?
Any help/idea/comment is welcome!
EDIT:
Last test with this:
force_ssl: [rewrite_on: [:x_forwarded_proto], subdomains: true, hsts: true, host: "${APP_URL}"]
result with the bad url: https://%24%7Bapp_url%7D/. So I think this is working but the var: "${APP_URL}"isn't converted to the real value. I'm digging on this.
By hardcoding the host: "${APP_URL}" value resolves the problem as suspected in my last edit.
There's something wrong here because all other ENV_VAR are replaced by their values but not this one.

AWS Loadbalancer "OutOfService"

I recently set up an ELB for my apps instance. However i keep getting OutOfService error message.
After a quick check, i realized that my apps always redirects any HTTP request from:
xx-xxx-xx-xxx.ap-southeast-1.compute.amazonaws.com to mydomain.com
My EC2 Public IP to mydomain.com
It's just how the app behaves. Hence everytime ELB tries to ping at port :80 it always fails, since the app response with HTTP 301 redirection.
I wonder if there is a work around to mitigate this problem. Can anyone point me to the right direction.
By the way the web app i am talking about is Prestashop.
Set up a "health check" route, dummying like /test that returns 200 if everything is ok on the instance. Tell the ELB Health Check to test that instead of /

How to get tomcat to send redirects as https urls when apache handles ssl

I'm a bit out of my depth here and nothing I have found quite addresses my problem. Si any and all suggestions are most welcome.
I've got tomcat6 running on CentOS 6.5 hidden behind an apache server (v2.2.15) and I am using Apache's mod_proxy to expose the tomcat webapps, which are running on port 8080. The tomcat hosts one production application and several development applications. On the apache side, both a Drupal site and the aforementioned tomcat production application are on the same domain and, thanks to rewrite rules, all requests to this domain are changed to https. The development sites are reached via subdomains and do not get re-written as https requests.
For the most part, this arrangement works fine. But parts of the tomcat apps are AJAX (calling a Java Struts 1.2 backend). Most of those requests are handled OK. But a few AJAX requests result in redirects (i.e., forward.setRedirect(true)) and that redirect is http (I guess because the container itself is not secure). As a result, I run into cross site scripting issues. I imagine I can use CORS headers to avoid the problem. But that seems like a hack. Is there a relatively painless way I can use to have tomcat send redirects back as https without making tomcat handle ssl directly?
Cris
You could configure the RemoteIpValve in Tomcat:
Another feature of this valve is to replace the apparent scheme
(http/https) and server port with the scheme presented by a proxy or a
load balancer via a request header (e.g. "X-Forwarded-Proto").
To configure Apache to forward the original protocol in the X-Forwarded-Proto header, add a RequestHeader directive in your Apache config, e.g.:
<VirtualHost *:443>
RequestHeader set X-Forwarded-Proto "https"
...
Note that in Tomcat 7, there is also a RemoteIpFilter.
You don't need to do anything special. It already works. Make sure you set the "redirectPort" in server.xml to Apache's HTTPS port, usually 443, and add the following to your <security-constraint> sections for resources you want secured by HTTPS:
<user-data-constraint>
<description>HTTPS</description>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</‌​user-data-constraint>
Late to the game here but others may find this-- we had a similar setup and issue where everything worked fine until the application started using ajax posts which did redirects for the response. The fix was to use mod_header in apache to rewrite redirects using "Header edit Location"
http://httpd.apache.org/docs/current/mod/mod_headers.html
Header edit Location ^http://www.example.com/ https://www.example.com/
This went unnoticed prior to the ajax redirects because the browser has no problem doing page level redirects to http (which apache would then redirect back to https). But the ajax cross-site prevention halts at the initial http missing out on that would then be redirected to https by a subsequent request.

Redirection on Apache (Maintain POST params)

I have Apache installed on my server and I need to redirect from http to https. The reason for this is our load balancer solution cannot hand https so requests come in on http and then we transfer them to https using the below lines in the httpd.conf file.
<VirtualHost 10.1.2.91:80>
Redirect 302 /GladQE/link https://glad-test.com/GladQE/link.do
</VirtualHost>
This works fine for GET requests but POST requests will lose the parameters passed on the URL. What would be the easiest way to perform this redirect and maintain POST params?
I need to get from http://glad-test.com/GladQE/link.do to here https://glad-test.com/GladQE/link.do maintaining POST params
Thanks
Tom
You can try with the HTTP status code 307, a RFC compilant browser should repeat the post request.
Reference: http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
In contrast to how 302 was historically implemented, the request
method is not allowed to be changed when reissuing the original
request. For instance, a POST request should be repeated using another
POST request.
To change from 302 to 307, do that:
<VirtualHost 10.1.2.91:80>
Redirect 307 /GladQE/link https://glad-test.com/GladQE/link.do
</VirtualHost>
Standard Apache redirects will not be able to handle POST data as they work on the URL level. POST data is passed in the body of the request, which gets dropped if you do a standard redirect.
You have an option of either using a PHP script to transparently forward the POST request, or using a combination of Rewrite (mod_rewrite) and Proxy (mod_proxy) modules for Apache like follows:
RewriteEngine On
RewriteRule /proxy/(.*)$ http://www.example.com/$1 [P,L]
P flag passes the request to the Proxy module, so anything that comes to your site (via GET or POST doesn't matter) with a URL path starting with a /proxy/ will transparently be handled as a proxy redirect to http://www.example.com/.
For the reference:
http://httpd.apache.org/docs/current/mod/mod_rewrite.html
http://httpd.apache.org/docs/current/mod/mod_proxy.html
Either your public facing website MUST use SSL to protect confidentiality or there is no sensitive data enver passing through it, and no possibility that your site will ever be used for a lauinchboard for sslstripping (there's a very good reason why Google serve up search results over HTTPS).
If you are not encrypting traffic between browser and your site then why are you trying to encrypt them between your load balancer and your webserver? If you do happen to have a SSL termination outside the load balancer (a very silly approach) then using HTTPS between the load balancer and the webserver is far from efficient. The question also implies lots of other security problems like session fixation/sniffing and SSLStripping vulnerabilities.