3

I'm building a fairly simple web application at the moment but because I have plans on turning this into sort of a multi-project portfolio app, I've decided to decouple the back-end and the front-end. That way I can easily integrate my other projects into this front-end.

At the moment I have a public GET route that anyone can visit to see info about a project (api/project/id), this only fetches data from the corresponding ID and returns a JSON collection. I then use React to consume it and display the data.

Since this part is supposed to be publicly accessible I can't use JWT or user authentication to protect it, and you can't delete, edit or put things into the database from it. It's not insecure because all you can do is read data from the project with ID (which is properly escaped).

But this also means anyone can look at my React code, find the API link and then use my JSON data (for whatever reason). I don't think it's really a problem but is there anyway you can protect the public endpoint so that only my server can actually use it?

The back-end is on port 8080 and the front-end is on port 80. The back-end is PHP, both the front-end and back-end is served by nginx. CORS is enabled since they are on two different ports.

I know I can check the origin header and match it against my front-end but surely the origin header can be spoofed. I can't use authentication since it is supposed to be public but I'd like it to be only accessible to my server and then publicly displayed.

Maybe I can reverse proxy it somehow so they both listen on 80 while still being on two different ports? I have UFW on my server, can I only allow connections to port 8080 from my own server IP/domain? Can I check the IP of the request to the back-end, since my front-end is requesting it then in my API I should be able to only allow my own servers IP to access it?

I hope you understand what I mean and I understand that it might be a non-issue because in the end all they can do is read data that they can anyways read by just going to the "intended" front-end site. But at the moment I can use ajax from any computer/server to fetch the JSON data and that is basically what I want to prevent so that the only way to view the data is from it's "intended source/design" (i.e. via the front-end)

Basically an API for public content delivery but only allowing my server to access and display it.

Ecaz
  • 33
  • 4

1 Answers1

3

tl/dr: If you have a read-only endpoint that only serves public data, then don't bother to try to secure it further. It's not worth the time, and is impossible to do anyway.

You have a few misunderstandings here that are worth addressing.

It's not about blocking connections from outside your server

You're trying to make it so that your API endpoints only respond to your SPA. However, that is not the same thing as limiting connections only to your server. The reason is because your react app doesn't run on your server - it runs in the user's browser. Your server sends the React app to the client, which runs in their browser. As a result the API calls come not from your server but from your users' web browsers, potentially located around the world.

Of course the browser will helpfully send up the Origin header, letting you know that the request is being made on behalf of JavaScript that was hosted on your domain. As you note though this definitely can be spoofed, as any non-browser client can easily send up whatever Origin they want. In fact, every single aspect of the HTTP request can be spoofed by the client.

Therefore you want to block requests not coming from your app

Unfortunately for you this is quite literally impossible. You can take steps to make it harder, but since the app runs on the client's machine, a sufficiently dedicated adversary would be able to reverse engineer any and all parts of it until they learn how your protection works and could then reproduce it wherever they want. In essence, you are asking how to implement DRM.

While you certainly could try to implement some steps to make it harder for someone to make API requests to your server from outside of your app, in your particular use case it is highly unlikely that this would be worth the effort (especially for a demo app).

For broader context, if I were looking at a demo app of a candidate and saw that they implemented some ad-hoc DRM solution to try to keep people out of an otherwise anonymous endpoint, then I personally wouldn't consider this a good thing. The most important part of security is learning to balance the risks and benefits, since any security measure inherently has some cost (if only the cost to develop it). In particular any time spent implementing security features takes time away from feature development. Most companies screw up by spending no time on security and more time on features, but there is an opposite side of that coin too. Taking time to try to secure an endpoint in a way that cannot actually be done effectively is a poor way to spend time when there are always more features to implement! Note, I don't say this to criticize your question or your thought process (which demonstrate a lot of forward thinking!), but rather to help you understand the broader "landscape" that you find yourself in.

Summary

In short, if you have a read-only endpoint that only serves public data, then don't bother to try to secure it further. It's not worth the time, and is impossible to do anyway.

Conor Mancone
  • 29,899
  • 13
  • 91
  • 96
  • Thank you for the answer! I somehow totally forgot that the client is the one actually sending the request. I've been learning Node on the side, maybe that's why... Anyways, you're totally right about risk vs benefit and since it's read only there is no real data risk and since the data is publicly available it really serves no benefit either. I guess I was more curious than concerned since I've only recently started working more "decoupled/headless" instead of monolithic. Again, thank you for the great answer! – Ecaz Jan 09 '20 at 13:26
  • 1
    @Ecaz Indeed, and again I want to emphasize that (especially that last paragraph of mine) wasn't meant to imply that your thought process was crazy or that you had a terrible idea. Rather I just wanted to emphasize the most important rule of security, which is that security is not a binary proposition. There is no "Secure" or "Insecure", only "secure enough". Getting good with security mainly means understanding threats and making sure that all parties involved are aware of the current risks and are okay with the chosen balance point between cost and benefit. – Conor Mancone Jan 09 '20 at 13:38