CSRF with a dockerized Flask application on AWS Fargate - docker

I made a docker container with a pretty simple web app: https://github.com/liquidcarbon/dockerflask2fa
The whole thing behaves well locally and when you're accessing via the ELB endpoint:
http://dockerflask2faloadbalancer-f10e5f558aaa921f.elb.us-east-1.amazonaws.com:5000
But when I use my Cloudfront distribution that lives on my domain, logging in does not work, returning "CSRF tokens do not match" message on registering a new user, and or logging in as an existing user.
https://flask.albond.xyz
The Cloudfront Cache Policy was set to CachingDisabled.
I'm new to web security, and I'll appreciate your help.

Looks like the caching & cookies behavior needs to be tweaked in Cloudfront: https://github.com/liquidcarbon/dockerflask2fa

Related

How to set up redirect uri for Facebook oauth authorization using dotnet core on docker when running behind IIS reverse proxy

We are building a web application with dotnet core running inside docker containers. We have put the app behind IIS on WS2016 which is used as reverse proxy. The requests incoming to our URL (www.myurl.com) are forwarded to the related docker container using the container name as the hostname with the help of url rewrite module(in our case, let's call it "web"). This setup works up to here.
However, a few days ago we needed to add Facebook oauth authorization support to register to the system and a problem appeared. We setup our authorization as the following:
...
services.AddAuthentication().AddFacebook(o =>
{
o.CallbackPath = new PathString("/account/facebookreturn");
o.AppId = appSettings.FacebookLogin.AppId;
o.AppSecret = appSettings.FacebookLogin.AppSecret;
})
...
Our facebook authentication challenge then redirects user to facebook oauth page with the following redirect uri:
https://www.facebook.com/v2.12/dialog/oauth......redirect_uri=http%3A%2F%2Fweb%2Faccount%2Ffacebookreturn&state=....
As you see the redirect_uri has the container name / hostname of the docker container whereas it should actually be "www.myurl.com".
We tried several solutions such as using x-forwarded headers. Using UseIISIntegration() and UseUrls did not seem to work either. What are we missing here? I am not much experienced with IIS and web headers, so it could be fairly obvious, and I appreciate the help.

AngularJS and Rails application security in AWS

I have an AngularJS front-end running on a Nginx server that sends requests to a Rails API backend running on a Puma application server. This application is running on an Amazon AWS EC2 instance.
The Rails API is listening on port 8081.
According to this architecture I had to open the HTTP port 8081 in AWS, so that I could receive the request from the front-end.
I have a domain, so It´s supposed all request should come from www.domain.com. However, I have noticed that if I use my EC2 instance name, such as, in example http://ec2-<ip>.eu-west-1.compute.amazonaws.com:8081/users the Rails API is serving all my users information.
How can I avoid this security bug. Where should I block this? In AWS configuration? In my Rails API CORS configuration? Any other place...
This seems an Authorization bug in your Rails API.
Who is the controller that answer to the route /users?
Let's say it is, for e.g., UsersController: in this case, you could have an action
def index
#users = User.all
end
or something similar, that returns the information you see.
Is difficult to give you a solution, without knowing if you need this action (maybe is just auto-generated boilerplate code) or if you want simply hiding it to who is not an Administrator...
Who wrote the Back End API should fix this for you based on your specifications.

Cloudflare + Heroku SSL

I have a rails app that is running on heroku and am using Cloudflare Pro with their Full SSL to encrypt traffic between: User <-SSL-> Cloudflare <-SSL-> Heroku, as detailed in: http://mikecoutermarsh.com/adding-ssl-to-heroku-with-cloudflare/ .
I am also using the rack-ssl-enforcer gem to force all http requests to go through https.
This is working properly, except I have the following issues, by browser:
1) Firefox. I have to add a security exception the first visit to the site, getting the "This site is not trusted" warning. Once on the site, I also have the warning in the address bar:
2) Chrome: page loads first time, but the lock in the address bar has a warning triangle on it, when clicked displays:
Your connection is encrypted with 128-bit encryption. However, this
page includes other resources which are not secure. These resources
can be viewed by others while in transit, and can be modified by an
attacker to change the look of the page. The connection uses TLS 1.2.
The connection is encrypted and authenticated using AES_128_GCM and
uses ECDHE_RSA as the key exchange mechanism.
Safari: initially loads with https badge, but it immediately drops off
Is there a way to leverage Cloudflare SSL + piggyback of Heroku native SSL without running into these security warnings? If not, I don't see much value in the configuration.
My apologies for slinging erroneous accusations against Cloudflare and Heroku :-)
Turns out the issue was not the fault of either, but instead that images on the app (being served from AWS S3) were being served up without https.
If anyone runs into this situation, lessons learned across a wasted day:
S3 only lets you serve up content via https if you serve from your bucket's dedicated url: s3.amazonaws.com/your-bucket-name/etc..
a) I tried setting the bucket up for static website hosting, so I could use the url "your-bucket-name.your-url.s3-website-us-east-1.amazonaws.com/etc...", and then set up a CNAME within my DNS that sends "your-bucket-name.your-url" to "your-bucket-name.your-url.s3-website-us-east-1.amazonaws.com/etc...", to pretty up urls
b) this works, but AWS only lets you serve via https with your full url (s3.amazonaws.com/your-bucket-name/etc..) or *.s3-website-us-east-1.amazonaws.com/etc...", which doesnt work if you have a dot in your bucket name (your-bucket-name.your-url), which was required for me to do the CNAME redirect
If you want to use AWS CDN with https, on your custom domain, AWS' only option is CloudFront with a SSL certificate, which they charge $600/mo, per region. No thanks!
In the end, I sucked it up and have ugly image URLs that looks like: https://s3-website-us-east-1.amazonaws.com/mybucketname...", and using paperclip, I specify https: with ":s3_protocol => :https," in my model. Other than that all is working properly now.

Multiple domains powered by one rails app

I am creating a blogging-like application where we allow our customers to use their own custom domain names such as domainexample.com, so each different domain serves the same application but with different content.
However I am struggling to figure out how to set this up on a production server. If my production server has a static IP then I can surely just set an a-record on each domain to the ip of the production server.
But what if the production server does not have a static IP. For example if we want to host it on heroku or engineyard? I have seen a few solutions online that require using rewrite rules but they require server restarts and cant really dynamically add and remove new domains as new users sign up. Does anyone know any good solutions to let multiple domains hit one rails app?
Heroku isn't your only option. If you can anticipate your customer's domains, have a look at this. If you can't, Rails routes constraints and a combination of the accepted answer to the question linked above should get you where you need to be going. Sounds like you wouldn't want to restart your server--so no editing of the routes. You might also make domains part of your models, or distinguish at the controller level or use URL rewriting in your web-server layer.
The problem, as I see it, is that Rails breaks its mantra of opinion over configuration here. There are many ways of serving up from multiple domains. That might be an intrinsic complexity, but the Rails Guides could at least document one possible solution.
If your customers just CNAME to your domain or create the A record to your IP and you don't handle TLS termination for these custom domains, your app will not support HTTPS, and without it, your app won't work in modern browsers on these custom domains.
You need to set up a TLS termination reverse proxy in front of your webserver. This proxy can be run on a separate machine but you can run it on the same machine as the webserver.
CNAME vs A record
If your customers want to have your app on their subdomain, e.g. app.customer.com they can create a CNAME app.customer.com pointing to your proxy.
If they want to have your app on their root domain, e.g. customer.com then they'll have to create an A record on customer.com pointing to your proxy's IP. Make sure this IP doesn't change, ever!
How to handle TLS termination?
To make TLS termination work, you'll have to issue TLS certificates for these custom domains. You can use Let's Encrypt for that. Your proxy will see the Host header of the incoming request, e.g. app.customer1.com or customer2.com etc., and then it will decide which TLS certificate to use by checking the SNI.
The proxy can be set up to automatically issue and renew certificates for these custom domains. On the first request from a new custom domain, the proxy will see it doesn't have the appropriate certificate. It will ask Let's Encrypt for a new certificate. Let's Encrypt will first issue a challenge to see if you manage the domain, and since the customer already created a CNAME or A record pointing to your proxy, that tells Let's Encrypt you indeed manage the domain, and it will let you issue a certificate for it.
To issue and renew certificates automatically, I'd recommend using Caddyserver, greenlock.js, OpenResty (Nginx).
tl;dr on what happens here;
Caddyserver listens on 443 and 80, it receives requests, issues, and renews certificates automatically, proxies traffic to your backend.
How to handle it on my backend
Your proxy is terminating TLS and proxying requests to your backend. However, your backend doesn't know who is the original customer behind the request. This is why you need to tell your proxy to include additional headers in proxied requests to identify the customer. Just add X-Serve-For: app.customer.com or X-Serve-For: customer2.com or whatever the Host header is of the original request.
Now when you receive the proxied request on the backend, you can read this custom header and you know who is the customer behind the request. You can implement your logic based on that, show data belonging to this customer, etc.
More
Put a load balancer in front of your fleet of proxies for higher availability. You'll also have to use distributed storage for certificates and Let's Encrypt challenges. Use AWS ECS or EBS for automated recovery if something fails, otherwise, you may be waking up in the middle of the night restarting machines, or your proxy manually.
Alternatively, there have been a few services like this recently that allow you to add custom domains to your app without running the infrastructure yourself.
If you need more detail you can DM me on Twitter #dragocrnjac

Rails 3, Authlogic, NGINX and HTTP basic authentication no working nicely together

I am in the early stages of building an app using Rails 3. User authentication is powered by Authlogic which I have setup pretty much as standard (as per the example docs) and everything is working as expected locally.
I have just deployed the app to a clean server install of Centos 5.4 / NginX / Passenger so staff can start to log in and enter content, etc. However, we're a long way from this being ready for public eyes so I have used NginX's basic auth module to keep the entire site behind another level of authentication.
Unfortunately Authlogic's authentication and NginX's basic authentication seem to be conflicting with one another. If basic auth is on then it is impossible to log in with Authlogic, yet if I disable basic auth then Authlogic works as expected.
I haven't posted any code as I'm really not sure what code would be relevant. I wonder whether this is a known issue and if there is any changes I can make to the configuration to get round the issue?
I can answer my own question (after several hours of looking in completely the wrong place). A good readup on Authlogic::Session::Config did the trick.
class UserSession < Authlogic::Session::Base
allow_http_basic_auth false
end
I still didn't try Rails 3, so my answer will be more general. And I don't know basic auth module for NginX.
If your team is connected localy, then you can create server accessible from local network only.
If you need access via Internet, then you can hide it behind VPN.
You can set access to site only through local ip and give ssh access to anybody who need it. It is easy to create socks proxy via ssh (in linux: ssh -D 8080 user#yourserver.com; where 8080 is port number, then set socks proxy in browser and you can lunch yoursever.com:3000).
I think that NginX allows you to set allowed IP's and deny other - so you can use it also for access restriction.
And also you can temporarly add to ApplicationController before_filter :require_login :), so only login page will be availbe to the world.
Hope it helps!

Resources