Change Node js server (on elastic beanstalk AWS) url to HTTPS - javascript

I am trying to deploy my React js app using an AWS s3 bucket. However, I am fairly new to AWS and am having quite a difficult time. This react app communicates with a node / express server, which is hosted on an elastic beanstalk environment. I previously had the following error:
Mixed Content: The page at 'https://myReactApp.s3.amazonaws.com/index.html' was loaded over HTTPS, but requested an insecure resource 'http://myElasticBeanstalkServer.us-east-1.elasticbeanstalk.com/signIn?username=lsharon&password=test4321'. This request has been blocked; the content must be served over HTTPS.
I began the process of trying to figure out how to "convert" my EB url into HTTPS. I found lots of information about obtaining an ssl certificate. I am pretty confused on the whole process. Here is what I did:
I do have a domain name, registered through google domains. I used it to obtain an ssl certificate. My ssl certificate is verified through the AWS certificate manager console. However, I am a bit confused how this relates to my node server which is hosted on elastic beanstalk. I connect to this API using the EB url...not my domain name. How can I use my ssl certificate to secure my server url?
I did find a little info about creating a hosted zone in Route 53, as well as adding 443 ports on the load balancer in my elastic beanstalk environment. However, I got lost pretty quickly. Do I just use a 443 listener in the EB environment, or do I also need a 443 process? Could someone explain this to me? Also, relating to the Route 53 hosted zone, do I create the hosted zone using my domain name, or my API (elastic beanstalk) url? And when I create an alias, where do I route the traffic to? My domain name, my EB url, or my s3 bucket?
Currently, when I load my static web page in the browser, it renders fine and says secure. However, when I click one of my buttons (therefore sending a fetch request to my EB url), it ALSO works but changes to insecure and says my ssl is insecure.
I do apologize for all the questions. I just feel rather lost and seem to be finding lots of information but can't seem to make it work quite right. If anyone could help me out, I sure would appreciate it.

To answer your first question, you have to setup DNS somewhere, either in your Google Domains account or in Route53 depending on who you want to use as your DNS host, pointing the domain name to the load balancer.
I connect to this API using the EB url...not my domain name. How can I
use my ssl certificate to secure my server url?
You have to change your front-end application to use the domain that matches the SSL certificate when making API calls (and also use https instead of http for those API calls). There is no other option if you want the web browser to stop complaining about these security issues.
To answer your second question, SSL certificates in AWS Certificate Manager can be attached to a load balancer which will handle terminating the SSL for you. The load balancer can still communicate with the EC2 instance using non-encrypted HTTP. So all you need to do is attach the SSL certificate to the port 443 listener in the load balancer.

Related

Can I permit geolocation for unsecured origins for development purposes?

I'm trying to develop a web app that uses javascript's geolocation functions. Since version 50, Google Chrome has blocked access to its geolocation functions for origins not using HTTPS. That's not a problem when I deploy my code to a production environment (which has a valid SSL cert), but for development I'm just using a hosts file entry to preview my code running on a local VM (specifically, Laravel's Homestead), which obviously doesn't have a valid SSL cert.
Is there a way to configure Google Chrome to permit access to the geolocation functions on my development VM, even though it's an "unsecure origin"? Alternatively, is there any way I can configure Homestead so that Chrome will believe that it's secure?
With your configuration (modifying hosts file to point the DNS of your domain to your machine), you can create a trusted certificate, using let's encrypt for example.
Just to mention it, http://localhost is considered secure, and chrome has a --unsafely-treat-insecure-origin-as-secure startup flag as mentioned by #4026 in his answer
The simplest answer to this question turns out to be that Homestead actually sets up self-signed certificates by default, so accessing your dev code via HTTPS works already, albeit with Chrome issuing an invalid certificate warning. However, if you accept that warning and agree to proceed to the insecure site anyway, Chrome allows the site to use Geolocation as though it were secure.
However, if that doesn't take your fancy, there are other options:
Set up Homestead with valid SSL certs
If you have a production webserver and control of a public domain name, you can use certbot to generate a trusted certificate on that server, and then copy the cert files to your Homestead box to use instead of the self-signed certs it auto-generates.
The disadvantage to this approach is that the certificates certbot generates are only valid for 90 days, so you'll need to repeat this process every three months (or any time you re-provision your Homestead box).
Add an A record to your DNS that directs the domain you want to use for development (say local-dev.yourdomain.com) to your production server.
Install certbot on the production server, and run certbot-auto certonly to generate a valid cert for local-dev.yourdomain.com.
Copy the files /etc/letsencrypt/live/local-dev.yourdomain.com/fullchain.pem and /etc/letsencrypt/live/local-dev.yourdomain.com/privkey.pem from your production server to your Homestead box.
Update your Homestead.yaml file to ensure that it directs requests for local-dev.yourdomain.com to the correct code directory on the box.
On your Homestead box, overwrite the files /etc/nginx/ssl/local-dev.yourdomain.com.crt and /etc/nginx/ssl/local-dev.yourdomain.com.keywith the fullchain.pem and privkey.pem files (respectively) that you downloaded in step 3.
Update the hosts file on your development machine to point local-dev.yourdomain.com to 192.168.10.10 (or whatever ip is specified in your Homestead.yaml file).
Access your site via https://local-dev.yourdomain.com and enjoy that hard-earned green padlock icon.
Explicitly configure Chrome to treat your (non-https) domain as secure
Chrome has a --unsafely-treat-insecure-origin-as-secure startup flag that can be used for this purpose, but it requires the use of a distinct user profile (settable via a second flag) in order to work.
From the Chromium wiki:
You can run chrome with the --unsafely-treat-insecure-origin-as-secure="http://example.com" flag (replacing "example.com" with the origin you actually want to test), which will treat that origin as secure for this session. Note that you also need to include the --user-data-dir=/test/only/profile/dir to create a fresh testing profile for the flag to work.
For development purposes, I use ngrok. You can get a secure tunnel to localhost. This allows to debug webhooks locally, test mobile apps or APIs with the backend mapped to http or https, really simple to install and use.
ngrok official site

What is the correct CORS entry for limiting an http:// connection to a remote, hosted web server from a grunt web server on a home network?

I've setup a remote, hosted javascript server (DreamFactory Server http://www.dreamfactory.com/) that responds via REST API's.
Locally, I'm running an Angularjs application through the grunt web server via $grunt serve
https://www.npmjs.com/package/grunt-serve
I have setup CORS on the remote server to allow '*' for multiple http:// connection types. THIS WORKS CORRECTLY.
My question is how I can limit the CORS configuration to only allow a connection from my home, grunt web server?
I've tried to create an entry for "localhost", "127.0.0.1", also my home Internet IP that is reported from whatismyip.com, the dns entry that my provider lists for my home IP when I ping it, a dyndns entry that I create for my home internet IP... None of them work, except for '*' (which allows any site to connect).
I think it is an educational issue for me to understand what that CORS entry should look like to allow ONLY a connection from my home web server.
Is this possible? If so, what and where should I be checking in order to find the correct entry to clear in the CORS configuration?
-Brian
To work and actually apply restrictions, the client requesting the connection must support and enforce CORS. In an odd sort of way (from a security point of view), restricting access using CORS requires a self-policing client (one that follows the prescribed access rules). This works for modern browsers as they all follow the rules so it generally works for applications that are served through a browser.
But, CORS access restrictions do not prevent other types of clients (such as any random script in any language) from accessing your API.
In other words, CORS is really about access rules from web pages that are enforced by the local browser. It doesn't sound like your grunt/angular code would necessarily be something that implements and enforces CORS.
If you really want to prevent other systems from accessing your DreamFactory Server, then you will need to implement some server-side access restrictions in the API server itself.
If you just have one client accessing it and that client is using "protected" code that is not public, then you could just implement a password or some sort of logon credentials and your one client would be the only client that would have the logon credentials.
If the access is always from one particular fixed IP address, you could refuse connections on your server from any IP address that was not in a config file you maintained.
You can't secure an API with CORS, for that you will need to implement an authentication scheme on your server. There's essentially 4 steps to do this.
Update the headers your server sends with a few additional Access-control statements.
Tell Angular to allow cross-domain requests.
Pass credentials in your API calls from Angular.
Implement an HTTP Authentication scheme on your web server or in your API code.
This post by Georgi Naumov is a good place to look for details of an implementation in Angular and PHP.
AngularJS $http, CORS and http authentication

How to call a web api via ajax over SSL from a local html file?

I have a local html file in may desktop accessing a web api (JAX-RS) that responds with some JSON data. I enabled CORS and everything works fine, but only without SSL. How can I do to make it work with SSL? I use a self-signed certificate and can call this web api from a WPF application, but from a JavaScript application (standalone html file), when Chrome sends the OPTIONS pre-flight before the POST, the request seems not to even reach the server. I also tried to import the self-signed certificate in the browser, but nothing has changed.
The preflight request is not allowed to include an entity body or credentials. If you are using preflighted requests then you cannot use two way SSL.
The solution is to change the server to make the certificate optional. I've only done this using Apache HTTP server or Tomcat but I assume other servers are also capable of this.
In apache the setting should be changed to
SSLVerifyClient optional
and in Tomcat the SSL settings should be changed to
clientAuth="want"
Without this change only CORS simple requests will work.

Google Earth api allow https connection with unregistered certificate

Is it possible to allow "insecure" https connection to load a kml file from server? Because now if it gets https error it does not load kml. Google Earth loads kml but asks for approval, api just does not do anything...
Nope.
This is one of my major gripes with the plugin. It'll only pull data off an HTTPS connection if there are no errors. This means that:
The SSL certificate must be valid
The SSL certificate must be trusted
There can be no authentication prompts
Passthru authentication that produces no prompting works fine
The only workaround I've found is to go in and manually trust the certificate on the client's machine. Make sure you trust the certificate in each browser that will be used (Chrome, IE, Firefox).
After speaking with Google directly about this -- I wonder if this is something that can be solved, or if it's just one of the "brutal realities" put it place by the web browser container.

How to protect a private REST API in an AJAX app

I know that there are many similar questions posted, but none of them refers to an HTML/javascript app where the user can access the code.
I have a private REST API written in nodejs. It is private because its only purpose is to server my HTML5 clients apps (Chrome app and Adobe Air app). So an API key is not a good solution since any user can see the javascript code.
I want to avoid bots creating accounts on my server and consuming my resources.
Is there any way to acomplish this?
An API key is a decent solution especially if you require constraints on the API key's request origin; consider that you should only accept an API key if the originating web request comes from an authorized source, such as your private domain. If a web request comes from an unauthorized domain, you could simply deny processing the request.
You can improve the security of this mechanism by utilizing a specialized encoding scheme, such as a hash-based message authentication code (HMAC). The following resource explains this mechanism clearly:
http://cloud.dzone.com/news/using-api-keys-effectively
What you want to do is employ mutually-authenticated SSL, so that your server will only accept incoming connections from your app and your app will only communicate with your server.
Here's the high-level approach. Create a self-signed server SSL certificate and deploy on your web server. If you're using Android, you can use the keytool included with the Android SDK for this purpose; if you're using another app platform, similar tools exist for them as well. Then create a self-signed client and deploy that within your application in a custom keystore included in your application as a resource (keytool will generate this as well). Configure the server to require client-side SSL authentication and to only accept the client certificate you generated. Configure the client to use that client-side certificate to identify itself and only accept the one server-side certificate you installed on your server for that part of it.
If someone/something other than your app attempts to connect to your server, the SSL connection will not be created, as the server will reject incoming SSL connections that do not present the client certificate that you have included in your app.
A step-by-step for this is a much longer answer than is warranted here. I would suggest doing this in stages as there are resources on the web about how to deal with self-signed SSL certificate in Android (I'm not as familiar with how to do this on other mobile platforms), both server and client side. There is also a complete walk-through in my book, Application Security for the Android Platform, published by O'Reilly.

Categories

Resources