3

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:

  1. Since Project A and Project B will be in two separate domains. Will AJAX work in this scenario? Because I've read that I have to work with JSONP if I'm planning to retrieve data from another domain. How secure is JSONP?
  2. Assuming I do implement OAuth, how will I manage my security keys for token encryption/decryption? Initially, what I was thinking was Project A to be a simple Java project which can basically store the secret keys and poll from my web service. That way, problem #1 can be resolved since I can just plainly use a simple AJAX function. But, I feel that it's quite unnecessary to make a Java web project just to store the keys and poll the information from the web service. My concern here is that, if I don't make it a Java project, I don't know where to store my keys. Surely, I won't store/expose it in the JS code.

Which leads me to ask, is OAuth 2.0 the right way to go? Or are there any other simpler alternatives?

mpmp
  • 2,409
  • 4
  • 33
  • 46
  • Have a look at my post in http://stackoverflow.com/questions/32505035/secure-http-communication-for-components-of-commercial-product/ – Ravindra babu Sep 22 '15 at 05:37
  • Can project A get a token from a Project A server at the time the Javascript app is requested? This would allow the Project A server to secure the keys and authenticate against Project B server. The resulting OAuth 2 session token could then be passed to the Javascript app. – Steve E. Sep 22 '15 at 20:09
  • @SteveE. Project A is the Javascript app. I haven't thought about creating just another project for tokens. – mpmp Sep 22 '15 at 20:20
  • Understood @miguel-portugal. Just looking for options to avoid storing authentication credentials in Javascript. Is Project A a manually triggered script so that it could ask a user for the OAuth credentials on startup and then forget them after authentication had taken place? – Steve E. Sep 22 '15 at 20:34
  • @SteveE. That's exactly my problem. I don't want to be storing credentials in JS itself. Project A is just a static HTML page and it will be accessed by the public. – mpmp Sep 22 '15 at 20:41
  • If Project A is accessed by the public/anybody. Is it just reading contents from Project B? In this scenario, what is gained by authenticating the connection between Project B and Project A? Once it arrives at Project A, it is in the public domain anyway. – Steve E. Sep 22 '15 at 20:52
  • @SteveE. That's true. I just don't want an external program (like some HTTP client), besides Project A, to have access to my web server. I want it to be like when Project B sees a request from Project A, B will be like "oh okay, you're a request from Project A, you can get whatever you want" but if it's a request coming from another resource (lets say an attacker just wanted to access my web server), B will reject it with a 403. Does it seem unreasonable? I never really dealt with cross domain security before which is why I'm asking. – mpmp Sep 22 '15 at 20:57

3 Answers3

1

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.

konqi
  • 5,137
  • 3
  • 34
  • 52
  • Thanks for the clearer explanation. With regards to asymmetrical encryption, where should the public keys be stored? Assuming that it's just a plain static JS page that will connect to the web server? – mpmp Sep 29 '15 at 22:54
  • You can store public keys everywhere. Those are not secret. But every client would have to create its own secret key and send the public key half to your server where you'd have to establish a trust relationship to the client with that key. The SSL handshake does pretty much the same thing when negotiating for a symmetic key for the communication. Actually you could use that as well but that requires every client to install a certificate. – konqi Sep 30 '15 at 07:51
  • Truth be told i would not use asymmetric encryption even though it's a great way to do it in theory. I would rely on transport security and use something rather simple like a plain text or digest authentication which hands out a session token, which is valid for a certain timespan. If you want OAuth 2.0 somewhere in the mix, take a look at OpenID Connect (http://openid.net/connect/). But if you have your own users that requires you to create your own authentication auf authorization Service. I used Apache Oltu for that once but there are a couple others, probably ones that are easier to handle – konqi Sep 30 '15 at 07:57
0

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.

Steve E.
  • 9,003
  • 6
  • 39
  • 57
  • I like the design you mentioned in Part 2. It seems plausible, however, I have no idea how to implement it properly. Is this a known security tactic? If it is, what is it called? If not, then any articles on how to implement this? – mpmp Sep 22 '15 at 22:28
  • What language/framework are you using to write Project B on your server stack? – Steve E. Sep 23 '15 at 09:38
  • Java on Project B. Planning to use the Jersey framework – mpmp Sep 24 '15 at 22:15
0

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.

jfcorugedo
  • 9,793
  • 8
  • 39
  • 47
  • 1. What do you mean by "Project A server to be a proxy of Project B"? My situation right now is I don't even know if I will need a web application for Project A because it seems like it could just run as a static HTML website. I just find it unnecessary to run Project A from a container since all data will be coming from an external server to be polled by Project A. 2. Where should I store the access token? As plaintext on the JS code? Isn't that susceptible to hacking? I mean if other people see the token, then they can use it to access Project B. – mpmp Sep 24 '15 at 22:15
  • Well, you're right in that you can store your project A sources in a web container (ngix, Apache...), but you can configure your web server to route API request to your project B server, so you can avoid using JSONP. Another option is to configure your projectB's server to send CORS headers, so your application can connect with both URLs using Ajax requests (see https://spring.io/guides/gs/rest-service-cors/). – jfcorugedo Sep 25 '15 at 12:52
  • There's no problem of storing the token in plain text if you use Session Storage, because only those tabs that have been loaded from your server can access this information. Moreover, data stored in session storage is not persistent. It will be deleted every time the user close the browser – jfcorugedo Sep 25 '15 at 12:53