Scenario:
Say I have a RESTful http(s) API running somewhere exposed on a public IP+port, and now I want to make a simple front-end that interacts with this API.
Constraint: I want to use GitHub Pages to serve the front-end, and I would like to make the repository public.
Question: Is there a way to design the API such that only calls originating from the gh-pages website will be successful? That is, if someone were to fork the repository and run their own version of the front-end, could the API notice that the call does not originate from the "official" gh-pages site? I'm really wondering if there is something I can provide in the API call that would prove that the caller is calling from a certain, predetermined place.
If the front-end can be privately hosted I could have a shared secret stored on both servers and use that to authenticate, but I would ideally want to be able to host this via GitHub pages (removing the need to maintain a server my self). Can I somehow use the fact the gh-pages site would have a proper certificate from Github? Or would this certificate be available for all gh-pages sites similarly, and hence not useful to determine origin?
I hope the question is clear, any input would be very much appreciated!
The assumption that the requests are made from gh-pages is wrong. The requests are made from the user's ip browser. Any user will load the contents of a web page in the browser from your own repository or from a fork repository, but the requests to the API will be created from the user's browser.
By default, the browser will not allow requests to an api on a different domain than the one where the html is loaded from. So, loading content from https://pages.github.com/ and requesting your own private server will fail, as it will be on a different domain (see CORS), but there are many ways to avoid this (see Cross-Origin Resource Sharing on GitHub Pages).
So, as long as CORS is enough for you (see above link how to enable requests to your api), you should not worry. Otherwise, there is not much you can do, but authorize the customers.
Is there a way to design the API such that only calls originating from the gh-pages website will be successful?
No.
The only information you have is what the client chooses to tell you.
A client might send a referer header. A custom client definitely can lie about that.
Related
I am using Nuxt (with SSR/ PWA/ Vuejs/ Node.js/ Vuex/ Firestore) and would like to have a general idea or have an example for the following:
How can I secure an API key. For example to call MailChimp API
I am not familiar with how a hacker would see this if a poor solution is implemented. How can I verify it is not accessible to them?
I have found a number of "solutions" that recommend using environment Variables, but for every solution someone indicates it wont be secure. See:
https://github.com/nuxt-community/dotenv-module/issues/7
https://github.com/nuxt/nuxt.js/issues/2033
Perhaps server middleware is the answer? https://blog.lichter.io/posts/sending-emails-through-nuxtjs and https://www.youtube.com/watch?v=j-3RwvWZoaU (#11:30). I just need to add an email to a mail chimp account once entered, seems like a lot of overhead.
Also I see I store my Firestore api key as an environment variable already. Is this secure? When I open chrome dev tools-> sources-> page-> app.js i can see the api key right there (only tested in dev mode)!
You could use either a server middleware or https://github.com/nuxt-community/separate-env-module
Middleware itself wont work because it can be executed on client too, and code that is used in middleware will be available on client
For #2 you can check whether its included in client js sources. There way more other way hacker to get anything e.g. xss, but its general things and not much related to your code.
How can I secure an API key. For example to call MailChimp API
The cruel truth here is NO... In the client side you cannot secure any kind of secret, at least in a web app.
Just for you to have an idea of the techniques that can be used to protect an API and how they can be bypassed you can read this series of articles. While it is in the context of an Api serving a mobile app, the majority of it also applies for an API serving a web app. You will learn how api-keys, ouath tokens, hmac and certificate pinning can be used and bypassed.
Access to third part services must be always done in the back-end, never on the client side. With this approach you only have one place to protected, that is under your control.
For example in your case of accessing the Mailchimp API... If your back-end is the one in charge of doing it in behalf of your web app, then you can put security measures in place to detect and mitigate the usage of Mailchimp by your web app, like a User Behaviour Analytics (UBA) solution, but leaving for the web app the access to the Mailchimp API means that you only know that someone is abusing it when Mailchimp alerts your or you see it in their dashboards.
I am not familiar with how a hacker would see this if a poor solution is implemented. How can I verify it is not accessible to them?
As you may already know F12 to access the developers tools is one of the ways.
Another ways id to use the OWASP security tool Zed Attack Proxy (ZAP) , and using their words:
The OWASP Zed Attack Proxy (ZAP) is one of the world’s most popular free security tools and is actively maintained by hundreds of international volunteers*. It can help you automatically find security vulnerabilities in your web applications while you are developing and testing your applications. Its also a great tool for experienced pentesters to use for manual security testing.
Storing secrets in the front-end is a big no no in terms of security.
If your website is using server-side rendering (aka SSG or static website) and is hosted on Netlify it sound like a perfect job for the Netlify functions (server side logic) and environnement variables.
You can find some documentations here : Netlify functions.
Netlify functions are powered by AWS Lambda.
You would typically create a function folder into your project directory and write your functions there. Functions are built after each deploy but you can test your functions locally with Netlify Dev
Here is an example of function using Mailchimp service wit injected secrets :
https://github.com/tobilg/netlify-functions-landingpage/blob/169de175d04b165b5d4801b09cb250cd9a740da5/src/lambda/signup.js
I think privateRuntimeConfig, by which secrets are only available on the server side is another workable solution here, if you're in a situation where you only need to access an API during Server Side Rendering.
https://nuxtjs.org/tutorials/moving-from-nuxtjs-dotenv-to-runtime-config/#misconceptions:~:text=privateRuntimeConfig%20should%20hold%20all%20env%20variables%20that%20are%20private%20and%20that%20should%20not%20be%20exposed%20on%20the%20frontend.%20This%20could%20include%20a%20reference%20to%20your%20API%20secret%20tokens%20for%20example.
I am using Angular 5 to send post request to send SMS through Bulksms : http://bulksms.com/
When making the request from Angular (client), I am facing this issue :
Origin http://TTTT:4200 is not allowed by Access-Control-Allow-Origin.
How can I correct this issue in BulkSMS ?
Regards,
Your browser's same-origin policy is restricting your Javascript code from accessing a third party (i.e. api.bulksms.com in this case) in the way in which you hoped to do it - and CORS (Cross-Origin Resource Sharing), which is a mechanism to relax those restrictions, is not relaxed enough to allow these requests (from you as an untrusted third party) either.
Wikipedia Same-origin policy : "Under the [same-origin] policy, a web browser permits scripts contained in a first web page to access data in a second web page, but only if both web pages have the same origin. An origin is defined as a combination of URI scheme, host name, and port number. This policy prevents a malicious script on one page from obtaining access to sensitive data on another web page". The Wikipedia page contains some good examples of the sorts of malicious Javascript code uses that the same-origin policy tries to limit.
It is important to note that these restrictions are only enforced by browsers: HTTP client code that is not running under a browser typically doesn't care about any of this.
For development purposes, there are some tools that can make your life easier - for example, you could use live-server to run a simple HTTP server which serves up your static files, while also using its --proxy option to route requests to api.bulksms.com and solve your same-origin policy problem in the process.
For production, a typical solution is to route your AJAX requests, which are destined for the third party service, via your own server (the one serving up your Javascript files to your browser), or a reverse proxy (which would front both your own and the third party service). If there is a server side to your application, you can make the HTTP requests to api.bulksms.com from there, using an HTTP client, and then have your Javascript code talk to your own server, to indirectly make the requests to bulksms.com. This also gives you the opportunity to add authentication headers on your server side, without your Javascript code ever having to know them (e.g. if you have one bulksms.com account, and many users able to use that account via your Angular app, but who should not know your credentials). Similarly, you could impose limits on what your Angular users can do in this way (e.g. to limit the number of SMSs they could each send per day).
I have an application that has a couple of features that I would like third parties business to avail of. for example the user information gets passed to us and we run ID checks and send back a token with information.
I think I can use a third party API management service like 3scale but what do I have to do on my end to 'expose' this API?
Thanks!
With AWS API Gateway, you can setup a simple http proxy to your application. Based on your needs, you can use features like auth, throttling, API keys management, client certificates etc.
Here is a blog explaining some of this.
Hope this helps, Ritisha.
As mentioned by Ritisha, API Gateway definitely can work, but it is sort of lock it.
I would recommend checking https://tyk.io/, which is an open source Gateway with commercial options. And for example it provides you Cloud version, where you do not need to expose any ports on your side at all. You just configure your API in dashboard and can just bind your CNAME record to the proxied API. This should work really well to try it out. And if you grow up this options, you can host it on your own, or use Hybrid environment, when all user requests come to your own server (no 3-rd parties), but on the other hand, have nice configuration dashboard in the cloud.
Hope it helps!
I'm working with a Point of Sale computer that is exporting a CSV file. I want to parse that file of inventory items. I want to download the product (search by SKU), update it with whatever is in the Point of Sale system, then send the updated product back to BigCommerce's API.
It seems like the whole API framework is designed around "apps" that end up in their appstore, of which this isn't the case at all.
I want to install a small .exe on a retail Point of Sale system that does an API call, not turn it into a web server and have to put SSL on it.
Is there a more straight forward way to work with the BigCommerce API then their "app store" route?
More digging around, I came back to this. So you really can't have any code running that isn't on a publicly available web server, even when you're developing? That can't be right.
To integrate with our single sign-on flow, your app must be a publicly
accessible web application. Choose your preferred language, framework
and hosting solution, and go from there.
If you do not want to set up an "app" using OAuth and an SSL certificate for your code you can use the Basic Authentication method for now. Note that this is deprecated and I do not know when exactly they will discontinue this method of authentication. If not wanting to go with SSL and an app at this point that is your best option.
Otherwise you can look at a self-signed SSL certificate if the app is just for your own code but this would again require setting up an app.
I faced a similar situation as yours. You can implement a oauth2 callback by setting up a SSL site on your machine using a self signed cert, say on port 8000. Then, while using the store owner creds 'install' your app from the my apps dashboard to obtain your token.
This is all assuming you've setup a page to handle the callback request and exchange the temporary token for your permanent one.
It's a bit painful starting out but once you get going its not so bad. I did everything in .NET.
Based on my discussion with their API team I wouldn't waste time with basic authentication if you're just starting out since you'll have to convert sooner than later anyways.
You definitely don't need a public SSL callback URL though if you aren't looking to create an app for their marketplace.
Hope this is of some help.
I think there is no solution for problem we're facing, but for confirmation I would like to you ask here.
We have REST API that is consumed from:
administration website (AngularJS)
customer website (AngularJS)
other REST API clients (own API applications)
Because requests from administration/customer website are made by AngularJS at a client side, users are able to determine (e.g. via FireBug) resources URLs and are able to consume all these resources from their own applications - what we don't want to and we cannot to restrict it e.g. with IP address because requests go from client. We would like to offer some group of resources only for customer / administration website and some resources for own REST API clients and some resources for both, but from the principle of JS requests made from AngularJS (and resource URL visibility) it cannot be done(?).
What could be the best practice for this issue?
Note: Your REST resources should always be secure. You should never depend on any client side javascript code. If your security is breached because someone knows the URI of an REST api; something is very wrong.
Angular can be made modular is such a way that the customers only see the customer modules and the administrators see the customer and administrator modules. This way you can let the administrators play in a WYSIWYG environment without having them to switch back and forth between the websites.
// Customers.js
// Module only containing customer code
angular.module('myCustomerProducts', ['myMainApp']);
// Administrators.js
// Module only containing administrator code
angular.module('myEditCustomerProducts', ['myCustomerProducts', 'myMainApp']);
Since your website is already separated for administrators and customers you can simply only include and deploy the javascript code for the specified target site. If this is not the case you'll need some server side transformation (eg. ASP.NET, PHP, Jade, ...) to build the index.html dynamically based on the credentials of the user.
Depending on the hosting platform, you can also deny access to everyone not in the administrator group when requesting anything from the administrator website (area).
But again; the server side security is way more of value. You can't secure an insecure server with javascript (on the client side).