How to secure an API used only from front-end (Ajax call) - javascript

Well, I created an API to manage for our websites some attachments uploads and store into Amazon S3 buckets
The scenario : Once visitor / user in the form and wants to submit it with attachment, once the file is selected then button clicked an Ajax request fire to the micro service API so it can store the file into S3 do some processing then return the direct link or identifier.
The question is : how can we authenticate the user using for example a short live token or something like that without being hijacked, mis-usage of the token..
In Javascript everything is visible to the visitor, and we try to not integrate any heavy process in the backend

If I got your question straight, you have a web interface in which files are uploaded to an S3 bucket and you need to make sure that in a certain back end API (such as REST) all file upload commands will have authentication and authorization.
The answer is highly dependent on your architecture but generally speaking, all Javascript calls are nothing but HTTP calls. So you need HTTP authentication/authorization. In general, the most straightforward method for REST over HTTP is the basic authentication, in which the client sends a credential in every single request. This may sound odd at first but it is quite standard since HTTP is supposed to be stateless.
So the short answer, at least for the scenario I just described, would be to ask the user to provide the credentials that Javascript will keep in the client side, then send basic authentication which the REST interface can understand. The server-side processes will then get such information and decide whether a certain file can be written in a certain S3 bucket.

Related

Github Secrets to Vanilla JS files

I am building a static website, HTML, CSS, and Vanilla JS. I came to a point where I have to use MailChamp to send emails to the client whenever there is a form submission. Not so tricky, docs are very clear on how to do an API call. But I need to send an API_KEY with every request. Which is a problem. I do not want to save this secret key in the code. I have added it as a secret on github repo. But I am not sure how I can access it on Vanilla JS files. I tried the following,
process.env.API_KEY and API_KEY
I am getting this error, sendEmail.js:1 Uncaught ReferenceError: process is not defined
Which makes sense, because it's a static website. But I cannot think of any other way. If it was a node process it would have been very simple :/
Let's say I create an API endpoint, and the server where I can securely save API_KEY, how would I authenticate the request coming from the front-end/static website? Assuming that I cannot securely save the token on the client side.
There is no way to do it the way you want, i.e. with pure front end (FE) because it would mean that you need to send your secrets to them.
Whatever you send to the front end will always be accessible to your users, so it's not safe.
What you need to have is the back-end (BE), some kind of server that will receive an async call from the FE, connect to the external API and do whatever you want it to do, and then send some kind of confirmation to the FE that the process was successful.
Now, the BE will know your secrets, and this is fine because you control it and the users won't have access to it directly.
Now, you do not always need a full-blown application for that, some people are getting stuff done with platforms like Firebase, that can handle authentication of users for example for you.

Best way to submit/retrieve data from external server, when you have access to external server but not the same domain server

I'm working on an SDK type thing for submitting data (including file uploads) to a service that I run.
I'm doing research, and trying to figure out the best way to submit data and get a response to an external server (my server) without being blocked by XSS restrictions.
The current setup is as so:
The customer hosts a server, and uses my server side library.
They generate a client page that loads the required JS from my server.
The client page requests data from my server (if it was not passed from the SDK on page load), and displays the information to the user.
The user then triggers an event, which submits data (potentially including file uploads) to my server (not the local server with the SDK library).
My server responds success or fail and the client JS handles it appropriately.
Some notes:
My server is a private PHP server that I have complete control over.
Although I could route all data through the customer's server (as they are using my library), it is not ideal, as it requires more set up for the customer, is slower for the end user, and handling file uploads is problematic as I want those files on my server, not theirs.
I thought perhaps the file upload inputs could be in an iframe. Will this allow uploads direct to my server?
Since the customer is using my library with an API key, I can authenticate the client's requests by passing an authentication token to the front end on page load that then gets passed to my server with whatever communication method ends up working.
I am open to changes in the architecture, but this is the ideal set up for me. I am just not sure what frontend methods are best for implementing this.
JSONP would work if you only need to make GET requests, but it sounds like you need to do POSTs as well since you mention file uploads.
For your case, Cross-Origin Resource Sharing (CORS) might work. The short explanation is that a browser will send an extra header named Origin if you make a request with XMLHttpRequest to another domain. Your server needs to respond with an additional header named Access-Control-Allow-Origin with a value of * or the value the browser sent in the Origin header. There are some nuances and gotchas when using CORS, so I recommend reading the link above for a thorough explanation.
With CORS set up, you should be able to use XMLHttpRequest to upload files.

Understanding how code flows from front-end to back-end?

I currently understand that in a full overview, a client will interact with the front-end of a website, then the website will process that transaction and perhaps create a file, the the file will go to the backend, backend will do something with the file (perhaps record it in a dbms), and then it will shoot a result back to the front-end.
For example, imagine we had a javascript website where users enter information which we want to record into a MySQL database. How does this process work? Obviously, we want to have an HTML in the website, and it the will "post" to a specific file. But, MySQL databases don't seem to exist as files, like I can't find a ".sql" file anywhere on my computer. Where do I exactly "post" to? And perhaps, once the user's information is recorded, I want the server to reply back with "You are the Nth submitter! Thanks." How do I exactly take information about a table in MySQL and respond with it?
The general high-level explanation of front/back end coding makes sense, but then when I get to actually trying to implement an example, I don't even know where to begin.
You post to an HTTP server (such as Apache HTTPD). The HTTP request includes a URL and the data.
The HTTP server uses something like mod_fcgid to map the URL onto a program (written in the language of your choice) using and passes along the request.
That program connects to the local database server and uses MySQL's custom protocols to send the query.
The local database server then stores the result in a file (which isn't a .sql file).

Keep an API call private/protected

I'm working on a web app that is mostly static - just HTML/CSS/JS + assets. I'm using a Rack server (Thin, actually) to serve it.
While the app is mostly static, there are a couple of server-side needs that have cropped up along the way. Since the app needs to interact with those needs via JavaScript, I've added Sinatra to the stack to allow me to easily set up some routes to serve as a simple API.
One such API call is to send an email - the web app needs a way to send an email to users. I set up a route (/api/mail) that can be called with a POST that includes a JSON object, and Ruby will fire off an email (via SendGrid).
Here's my issue - by nature, these API calls are public. Most of the time, that is fine - but with the email API, I want to protect it so that nobody can just start sending malicious emails with a simple POST, posing as my app.
Problem is, I'm not quite sure how to authenticate this. The web app itself is the client, not the user, so a password or API key seems worthless, since anyone could just sniff out the POST header and grab the credentials that the app is posting to the API.
Is encrypting everything via SSL my only option, or am I missing some glaringly obvious solution?
At the end of the day, anything you do can easily be scraped. I would do some aggressive rate limiting by ip and session, don't think if anything else would be possible (or effective)

Cloud API with JavaScript (Amazon, Azure)

I'm researching a possibility of using some cloud storage directly from client-side JavaScript. However, I ran into two problems:
Security - the architecture is usually build on per cloud client basis, so there is one API key (for example). This is problematic, since I need a security per my user. I can't give the same API key to all my users.
Cross-domain AJAX. There are HTTP headers that browsers can use to be able to do cross domain requests, but this means that I would have to be able to set them on the cloud-side. But, the only thing I need for this to work is to be able to add a custom HTTP response header: Access-Control-Allow-Origin: otherdomain.com.
My scenario involves a lots of simple queue messages from JS client and I thought I would use cloud to get rid of this traffic from my main hosting provider. Windows Azure has this Queue Service part, which seems quite near to what I need, except that I don't know if these problems can be solved.
Any thoughts? It seems to me that JavaScript clients for cloud services are unavoidable scenarios in the near future.
So, is there some cloud storage with REST API that offers management of clients' authentication and does not give the API key to them?
Windows Azure Blob Storage has the notion of a Shared Access Signature (SAS) which could be issued on the server-side and is essentially a special URL that a client could write to without having direct access to the storage account API key. This is the only mechanism in Windows Azure Storage that allows writing data without access to the storage account key.
A SAS can be expired (e.g., give user 10 minutes to use the SAS URL for an upload) and can be set up to allow for canceling access even after issue. Further, a SAS can be useful for time-limited read access (e.g., give user 1 day to watch this video).
If your JavaScript client is also running in a browser, you may indeed have cross-domain issues. I have two thoughts - neither tested! One thought is JSONP-style approach (though this will be limited to HTTP GET calls). The other (more promising) thought is to host the .js files in blob storage along with your data files so they are on same domain (hopefully making your web browser happy).
The "real" solution might be Cross-Origin Resource Sharing (CORS) support, but that is not available in Windows Azure Blob Storage, and still emerging (along with other HTML 5 goodness) in browsers.
Yes you can do this but you wouldn't want your azure key available on the client side for the javascript to be able to access the queue directly.
I would have the javascript talking to a web service which could check access rights for the user and allow/disallow the posting of a message to the queue.
So the javascript would only ever talk to the web services and leave the web services to handle talking to the queues.
Its a little too big a subject to post sample code but hopefully this is enough to get you started.
I think that the existing service providers do not allow you to query storage directly from the client. So in order to resolve the issues:
you can write a simple Server and expose REST apis which authenticate based on the APIKey passed on as a request param and get your specific data back to your client.
Have an embedded iframe and make the call to 2nd domain from the iframe. Get the returned JSON/XML on the parent frame and process the data.
Update:
Looks like Google already solves your problem. Check this out.
On https://developers.google.com/storage/docs/json_api/v1/libraries check the Google Cloud Storage JSON API client libraries section.
This can be done with Amazon S3, but not Azure at the moment I think. The reason for this is that S3 supports CORS.
http://aws.amazon.com/about-aws/whats-new/2012/08/31/amazon-s3-announces-cross-origin-resource-sharing-CORS-support/
but Azure does not (yet). Also, from your question it sounds like a queuing solution is what you want which suggests Amazon SQS, but SQS does not support CORS either.
If you need any complex queue semantics (like message expiry or long polling) then S3 is probably not the solution for you. However, if your queuing requirements are simple then S3 could be suitable.
You would have to have a web service called from the browser with the desired S3 object URL as a parameter. The role of the service is to authenticate and authorize the request, and if successful, generate and return a URL that gives temporary access to the S3 object using query string authentication.
http://docs.aws.amazon.com/AmazonS3/latest/dev/S3_QSAuth.html
A neat way might be have the service just redirect to the query string authentication URL.
For those wondering why this is a Good Thing, it means that you don't have to stream all the S3 object content through your compute tier. You just generate a query string authenticated URL (essentially just a signed string) which is a very cheap operation and then rely on the massive scalability provided by S3 for the actual upload/download.
Update: As of November this year, Azure now supports CORS on table, queue and blob storage
http://msdn.microsoft.com/en-us/library/windowsazure/dn535601.aspx
With Amazon S3 and Amazon IAM you can generate very fine grained API keys for users (not only clients!); however the full would be PITA to use from Javascript, even if possible.
However, with CORS headers and little server scripting, you can make uploads directly to the S3 from HTML5 forms; this works by generating an upload link on the server side; the link will have an embedded policy document on, that tells what the upload form is allowed to upload and with which kind of prefix ("directories"), content-type and so forth.

Categories