Reputation: 2459
I'm planning to create two projects.
One project will be a simple HTML/Javascript-centric project that uses AJAX to retrieve and poll data from a web service. Let's call it Project A.
The other project, Project B, is a RESTFul web service that simply caches data retrieve from external sources.
Basically Project B will serve as a web service to more than 1 more project. I will not be exposing Project B to the public. I just used Project A as an example project that will be polling from Project B.
I've read about OAuth 2.0 and it seems to be the best and most straight-forward way to prevent any other applications to access my web service. But here are some questions:
Which leads me to ask, is OAuth 2.0 the right way to go? Or are there any other simpler alternatives?
Upvotes: 3
Views: 365
Reputation: 5227
In contrast to what's been said here:
I believe OAuth 2.0 is not the way to go.
Why?
OAuth 2.0 is an authorization protocol and not an authentication protocol. It relies on a third party to provide authentication. That third party also stores who has access to what resources in case you want to reauthorize service usage. So OAuth 2.0 alone can never solve any authentication problem. If you want your application (in the terminology of oauth: the resource server) to be independant of other third parties that provide OAuth (authorization server) you would have to implement an authorization server yourself. You will have a limited amount of resource servers whereas OAuth is really meant to authorize service access accross multiple providers. Therefore I don't see how OAuth could solve your problem.
Whether JSONP is secure is actually a funny question.
What is JSONP actually? It's javascript adding a script tag in your DOM and make the browser load that additional resource. Whether it is secure or not is basically the same question as asking for the security of any communication between the browser and the server. It will be as secure as you make it. The same goes for AJAX with Access-Control-Allow-Origin, etc.
So what to do?
One thing first. If your application A is just static resources your do not need an application you need a content delivery network. That's how stackoverflow does it and that's how it'll outperform any server you could ever host yourself. There is that, and there are caching proxies like google's pagespeed (I have no idea if that product still exists, but it's only meant as an example).
Here are two more ideas:
If you want the communication between two applications secure you can use asymmetrical encryption. Exchange public keys and you can verify identity and safely transmit data. I'll leave it up to you to dig into the matter.
Also as Steve E. wrote but did not name properly you can use CSRF Tokens. I believe jQuery supports those for some time now, but the technique works equally well without jQuery. Again that is a matter I'll let you dig into.
Lastly
All this makes me think about reinventing the wheel. As long as your connection is secure you can do pretty much anything (including plain text authentication with reaaaaaally long string) as long as you are a tiny bit paranoid and put a bit of entropy into your authentication mechanism. Then again, how secure does it have to be? That is a question that is most of the time answered with 'absolutely secure' but in fact rarely is a real requirement.
Upvotes: 1
Reputation: 10059
Question 1
I don't like JSONP, so in my opinion your better choice is to make your Proejct A server a proxy for your Project B.
For example, if you're using NodeJS and Express to serve Project A requests, you can redirect all /api
requests to your Project B as follows:
app.use('/api', function (req, res) {
req
.pipe(request('https://projectB.com/' + req.url))
.pipe(res);
});
So your NodeJS will handle all request made from the browser except those ones that ends in /api
.
Another option is to configure your Project B server to send CORS headers in each request.
For example, if you're using Java, you can create a servlet filter that adds these headers:
@Component
public class SimpleCORSFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");//Instead of '*' use your own domain!
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}
Question 2 I think OAuth 2.0 seems to be the best choice in your current situation.
You should not store user password in your Project A application. Instead of storing passwords, your javascript application should store an access token, that will be used to access REST endpoints.
Besides avoiding security risk, by using token base authentication you can prevent a lot of headaches when your users change their passwords.
Furthermore you can use HTML 5 Session storage to store the access token (as well as the refresh token), because this information will be deleted when the user closes the browser and only the tabs loaded from your application domain can access this data.
If you finally choose token based authentication, you can code your own implementation to generate that token, but I think it's much better to use a well-known implementation. Moreover, there are a lot of frameworks that implements OAuth authentication in your server side in many languages: Java, python, Node, etc...
If you're using Java, take a look at some examples here using Spring OAuth.
The question now is Which authorization flow do you prefer?
OAuth provides a few different authorization flows. Based on the information you've provided, I think the best choice would be Resource owner password-based grant, because your users will trust your javascript application (Project A), so they will be confortable giving their credentials directly to your application.
Note: If you finally choose OAuth 2, make sure all your requests will get to server using HTTPS, because OAuth 2 doesn't include anything about cipher, because it assume your connections always use SSL.
Upvotes: 0
Reputation: 9353
Part 1. Yes AJAX can work and JSONP offers the most flexibility for cross domain and cross browser support.
JSONP works by adding new tags into the markup of the page which are not blocked by the Same Origin Policy (SOP) enforced on most other request types. The 'P' stands for Padding and refers to the JSON response being padded inside a Javascript function. This function must be executed on the client in order to retrieve the JSON data embedded in the function and bypass the SOP.
There are a number of potential security risks introduced by doing this. Firstly it depends on the browser running code from the remote server. If that server is compromised then it can inject anything it likes into your application. There has to be a strong trust of the remote server.
Secondly, other scripts running in the browser (On other tabs or windows) could also make requests to the remote webserver and steal the response data because the SOP doesn't apply to JSONP. This is more likely if cookies are used as the session identifier to the remote server. So you wouldn't use it for banking software.
If your app security requirement is low enough that you can live with those risks, then JSONP will get the job done. As you are trying to avoid having a server side app for Project A.
Alternatives:
Modern browsers support Cross-origin resource sharing. I've not used it enough to comment on how it may fit your needs.
Use subdomains of the same domain for hosting Project A and Project B. In this scenario, Project A could be on www.domain.com and Project B on webservice.domain.com. If both subdomains return content such as iframes which set 'document.domain = "domain.com"' then they could communicate.
I am not sure either of the above methods would be suitable for your scenario.
Part 2.
As discussed the purpose of the authentication is to reduce the likelyhood of 3rd parties making requests to your webservice. To make Project A easy for the public, it all needs to be in Javascript. This means that given time any system you implement is open to being reverse engineered and open to abuse.
Project B cannot guarantee that requests appearing to come from Project A are indeed doing so. However by making the request mechanism slightly obscure, you can at least mitigate against automated scripts and simple attacks. This will deter the less determined rogue users.
One option would be to have an extra initial request to Project B. This would return a random seed which is then used by Project A and Project B to calculate a token used on subsequent requests using a predetermined formula. Any request without an allowed token would be rejected. The token could be time limited by Project B. Project A would request a new seed when the previous one expired.
This mechanism can still be broken by an informed attacker and you would need to determine if that risk was acceptable for you application. Rate limiting of token requests and monitoring for unusual traffic patterns may also be prudent.
Upvotes: 0