Secure access to api only from chrome extension - javascript

I am working on allowing a chrome extension to post a new entry to my site via post data.
I want to be able to lock it down so only the chrome extension can post. If I get post data from anywhere else I want to reject it.
Does anyone know if/how this is possible or how you would go about doing it?

Unfortunately, validating clients (whether a Chrome extension, an Android app, an iOS app, client-side JavaScript, or some other client) from a web server is an unsolved problem.
There are some things that you can do to deter abuse and mitigate this problem such as:
Requiring user authentication (and rate-limiting usage per-user)
Rate-limiting access on the basis of IP addresses
Requiring tokens to be provided that are handed out in prior requests (this can be used to ensure that certain APIs are called in certain expected orders / patterns).
Showing a CAPTCHA or other challenge for anomolous or over-limit usage
While you can additionally check things such as user agent, referrer URL, or a token that you embed in the Chrome extension, with any distributed application, it is easy to reverse-engineer these and mimick them in a counterfeit app, and so these aren't true solutions.

You can add a simple check in the code.
Following code stops anyone who is trying to access your api outside the chrome extension.
if(substr($_SERVER['HTTP_ORIGIN'],0,19) !== "chrome-extension://") die("Not Allowed")

Related

How do you implement digest authentication with SHA-256 when modern web browsers disable SubtleCrypto when you're not in a secure context (https)?

I've got a very basic web server running on an ESP8266 microcontroller, so system resources are very limited, but I figure it can probably deal with SHA-256 (I'll guess we'll see, but that's a separate issue).
I've got the barebones digest authentication implementation working well enough that I can access the site via curl.
This microcontroller is not meant to be exposed to the internet, it's only something you'd access internally via your lan, so SSL isn't an option (not sure how well the microcontroller would hold up if it tried to support HTTPS).
So, here's my scenario:
User tries to access the site on the microcontroller from their favourite web browser. They are given a 401 code and redirected to a login page (along with the WWW-Authenticate header).
This login page needs to take the information from the WWW-Authenticate header, as well as the username and password input by the user and generate the hash it needs to send in an Authorization header.
Unfortunately, the built in functionality for generating SHA-256 hashes is disabled if you're not connected via HTTPS (according to https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto) - So does this mean that digest authentication is not supported by web browsers natively (unless they choose to use MD5 instead of something more secure)? If you're implementing digest authentication, you need to supply your own hashing functions?
I also don't quite understand why disabling the ability to do hashes helps user security (in a non-https context).
An assumption:
After a cursory google search, it seems that digest authentication only makes sense for http, as if you're using https then you've already got better encryption protecting your credentials.
So to answer my own question (partly):
It turns out that the user side is handled entirely by the browser (i.e. Generic login modal pop-up). Java script doesn't even have access to the response headers anyway.
I guess to prevent poorly implemented non-secure logins?
The examples I've seen work around it by providing functionality entirely via xhttprequests.
I still don't know what benefit denying access to hashing algorithms provides though

Setting up a development environment for working with 0Auth 2.0

I'm curious if anyone else has encountered this issue.
I am building an application that will authenticate users using Google 0Auth 2.0 + OpenID.
I've built a simple site just with HTML and CSS to hold the UI and I'm using live server in Vscode to view it.
In The Google developer console for oauth, you must set Authorised JavaScript origins for client-side applications. I assumed I would just set this to http://localhost:5500 for the port that live server uses but I always get the following error:
Authorization Error
Error 400: invalid_request
Permission denied to generate login hint for target domain.
I have got around the issue by just getting a domain and hosting for a test site and setting this as the "Authorised JavaScript origin". However is seems really clunky and I have to FTP all my files to my hosting provider every time I want to change my code.
I could also host everything on a Node.js server from my local machine but this would just cause the same issue as before.
My question isn't so much how to stop getting this error but what is the proper way of developing with OAuth 2.0 and is there any way to speed up the process/create a local environment that doesn't get the same errors.
Thanks for your help.
There is an answer to this Google question here that may help you.
The way I have always set up an OAuth environment is to try to avoid localhost and use more real world URLs on a Developer PC. I also like to split them like this which helps me to visualize the architecture:
Base URL
Represents
http://www.example.com -
Your web UIs
http://api.ecample.com
Your APIs
http://login.example.com
The Authorization Server
This approach can also give you more confidence that your code will work well in beowsers, in areas such as these:
CORS
Cookies
Content Security Policy
By default you just need to edit your hosts file and add an entry like this. It can work very well for demos to business people also.
127.0.0.1 localhost www.example.com api.example.com login.example.com
:1 localhost
ADVANCED SCENARIOS
At Curity we provide some quite advanced developer setups and this approach scales well, as in the below articles. The second of these also provides a script you can use to run locally over SSL, in case this is ever useful:
Single Page Apps End to End Developer Setup
Kubermetes End to End Developer Setup

"The owner of this website has banned your access based on your browser's signature" ... on a url request in a python program

When doing a simple request, on python (Entought Canopy to be precise), with urllib2, the server denies me access :
data = urllib.urlopen(an url i cannot post because of reputation, params)
print data.read()
Error:
Access denied | play.pokemonshowdown.com used CloudFlare to restrict access
The owner of this website (play.pokemonshowdown.com) has banned your access based on your browser's signature (14e894f5bf8d0920-ua48).
This is a apparently a generic issue, so I found several clues on the web.
https://support.cloudflare.com/hc/en-us/articles/200171806-Error-1010-The-owner-of-this-website-has-banned-your-access-based-on-your-browser-s-signature:
A firewall, proxy, a browser plugin or extension may be throwing a false positive. Try visiting the site with a different browser as an alternative way of accessing the site.
https://support.cloudflare.com/hc/en-us/articles/200170176-Why-am-I-getting-a-Checking-your-Browser-before-accessing-message-before-entering-a-site-on-CloudFlare-:
The "Checking your browser before accessing (insertsite.com) occurs when the site owner has turned on a DDoS protection and mitigation tool called "I'm Under Attack". The page will generally go away and grant you access to the site after 5 seconds.
Note: You will need to have both JavaScript and Cookies turned on in your browser to pass the check. The check is in place to make sure that you are not part of a botnet."
The answers are rather clear, except for this one thing ... *I'm not using any browser! The request is done trough a python program, with an urllib.urlopen request ...
Does this mean I'm supposed to have, like, cookies and JavaScript turned on in ... Enthought Canopy? Does this sentence makes any sentence at all? I barely understand anything about this browser specific check activating when trying to access the site with a basic request from a programming console. And that's why I ask for your help.
Why does it happen? How to bypass it?
What this site is "checking" is not your browser, it's the "user agent" - a string your client program (browser, Python script or whatever) eventually sends as a request header. You can specify another user agent, cf Changing user agent on urllib2.urlopen.
I just saw it with Safari from my home IP, looking at a site I author! After performing a login to cloudflare website and hitting refresh its back. Probably my mobile internet was too slow (in New Zealand) and the javascript did not load in time? I have DDOS protection and "under attack" enabled AFAIK.

CORS with IE11+ Access Denied with SSL to localhost

The Very Short Version: is anybody successfully requesting local resources via AJAX, in IE, over SSL? I cannot solve getting an "access denied" error.
The Longer Version:
I am using AJAX to retrieve JSON from an application that runs a local web service. The web service channel is encrypted so that if the remote site is being served over HTTPS, no "insecure resource on a secure page" errors appear.
So, in the address bar is a remote site of some sort... mysite.com. It is receiving information from https://localhost/.
The web service is setting correct headers for CORS and everything works in Chrome and Firefox. In IE, if I put my https://localhost resource into the address bar, the correct resource is returned and displayed. However, when using AJAX (not just the address bar), a security setting in IE is denying access. This is documented (in part) here:
Access denied in IE 10 and 11 when ajax target is localhost
The only proper solution in one reply is to add the requesting domain (mysite.com in this case) to the trusted sites. This works, but we would prefer to not have user intervention... pointing to a knowledge base article on how to add a trusted site is hardly a great user experience. The other replies to that question are invalid for the same reasons as below-->
Some more stumbling around and I discovered this:
CORS with IE, XMLHttpRequest and ssl (https)
Which had a reply containing a wrapper for AJAX requests in IE. It seemed promising, but as it turns out, IE11 has now deprecated the XDomainRequest API. This was probably the right thing for Microsoft to do... but now the "hack" workaround of adding a void onProgress handler to the XDR object is obviously not an option and the once-promising workaround wrapper is rendered null and void.
Has anybody come across either:
a) a way to get those requests through without needing to modify the trusted sites in IE? In other words, an updated version of the workaround in the second link?
b) as a "next best" case: a way to prompt the user to add the site to their trusted zone? "mysite.com wishes to be added to your trusted zones. Confirm Yes/No" and have it done, without them actually needing to open up their native settings dialogues and doing it manually?
For security reasons, Internet Explorer's XDomainRequest object blocks access (see #6 here) to the Intranet Zone from the Internet Zone. I would not be surprised to learn that this block was ported into the IE10+ CORS implementation for the XMLHTTPRequest object.
One approach which may help is to simply change from localhost to 127.0.0.1 as the latter is treated as Internet Zone rather than Intranet Zone and as a consequence the zone-crossing is avoided.
However, you should be aware that Internet Explorer 10+ will block all access to the local computer (via any address) when a site is running in Enhanced Protected Mode (EPM)-- see "Loopback blocked" in this post. Currently, IE uses EPM only for Internet sites when run in the Metro/Immersive browsing mode (not in Desktop) but this could change in the future.
No, there's no mechanism to show the Zones-Configuration UI from JavaScript or to automatically move a site from one zone to another. However, the fact that you have a local server implies that you are running code on the client already, which means you could use the appropriate API to update the Zone Mapping on the client. Note that such a change requires that you CLEARLY obtain user permission first, lest your installer be treated as malware by Windows Defender and other security products.
So, in summary, using the IP address should serve as a workaround for many, but not all platforms.
Since those are two different domains, one solution would be to create an application which proxies the requests in the direction you want.
If you have control over the example.com end, and want to support users who bring their own localhost service, this would be harder, as you would have to provide more requirements for what they bring.
If however, you have control over what runs in localhost, and want to access example.com, and have it access the localhost service, set up redirection in your web server of preference, or use a reverse proxy. You could add an endpoint to the same localhost app which doesn't overlap paths, for example, route http://localhost/proxy/%1 to http://%1, leaving the rest of localhost alone. Or, run a proxy on e.g. http://localhost:8080 which performs a similar redirection, and can serve example.com from a path, and the API from another.
This winds up being a type of "glue" or integration code, which should allow you to mock interactions up to a point.

Server-side flow for Google Drive API authorization of a javascript Chrome extension

I was reading #Nivco answer to Authorization of Google Drive using JavaScript and saw:
"...all you have to do it is use server-side code to process the authorization code returned after the Drive server-side flow (you need to exchange it for an access token and a refresh token). That way, only on the first flow will the user be prompted for authorization. After the first time you exchange the authorization code, the auth page will be bypassed automatically.
Server side samples to do this is available in our documentation."
Having read the documentation I am still pretty confused about how to process the authorization code and ultimately pass the access and refresh tokens to my Chrome extension so that it can proceed without the server for future requests. Can someone provide an example of the server-side code to do this?
As background I have a Chrome Extension with several thousand users that is built on the Google DocList API but I am trying to transition to the Drive API since the other one is being deprecated. Ideally my code would be entirely stand alone as an extension but I'm willing to accept the single authorization request through my server that Nivco's answer requires.
Thanks!
We've just ported our JavaScript application from using server to client flow. We've removed the server part entirely, it's not needed any longer.
You can see the source code that we used online, it's available uncompressed.

Categories

Resources