0

I'm finding it really hard to find a solution to make secure requests via our API without a potential hacker being able to see sensitive secret information via Google Chrome dev tools (or any browser's dev tools), as React tends to show everything that's client-facing. Our backend hosts Stripe payment info (which may or may not be useful for a hacker), but also private user data.

The API endpoints we wish to protect are from frontend to backend, and they specifically retrieve user data from a MySQL table and backend scripts for features. It's for a public content platform, like YouTube or SO, where content is available for everyone whether they're logged in or not. (we have endpoints to show what content we want to display on the site and where - however each user has sensitive information that should remain private. I basically don't want anyone to get access to the MySQL user table).

Our Back-end and API use Laravel & PHP, and our Front-end uses React.

The current security set up is a password key that allows us to access our API, which changes every hour. Every hour, the key changes, and we use an endpoint to refresh the key (we have a 'master key' that doesn't change that allows us to do this). We pass this in the Authorization header. The issue with this is, a hacker can see this master key in dev tools. The header does not hide the key.

I've been exploring potential solutions, and these are the three potential solutions I've come across:

Solution 1: Send an encrypted token from the Authorization Header and decrypt it in the backend

Making a frontend request /requestToken that sends an encrypted token that is unique every time - only we just need to know the rules around building that token. Our backend knows how to decrypt it because it's in our special format.

A hacker will have to know the rules of how to build the token (they won't be able to copy and paste an existing one that they see in the front-end), as the token will be time unique, with any given token only being valid every 5 seconds.

This strategy is way more secure than our current one, but an issue I have with this is that a hacker can a) figure out how the token is encrypted because they can see it being built every time they make a request b) they can copy an existing token and use it for 5 seconds, and c) this encryption and request are happening on the front-end and so it can be seen by a hacker.

Issue: Everything happening on the client-facing React app is accessible publically (Source). I would use the solution in the link I just referred to, but it seems that it is for third party APIs rather than for an API that links our frontend to our own backend.

Solution 2: Laravel CSRF with React integration

Using Laravel's native CSRF tokens, and using it with React's frontend (not sure how to but scrolling to the bottom of this page gave some instruction). I have spoken to a few devs who have advised me to use Laravel Sanctum, but isn't it for SPAs (Single Page Apps)? My website has more than one page.

Solution 3: Using JWTs?

For JWTs, I found this solution, but it doesn't apply to me because my site doesn't require people to log in - and it seems that that solution requires people to log in in order for the API to be protected because it uses a password grant generated after a user has successfully logged in.

Which of these strategies are the best if any?


As you might be able to tell, I'm not a developer myself - I'm just trying to find someone who can help me protect my site's user data (which contains Stripe customer info in it, so the data is very important!). However, first of all, I need to agree on the best infosec strategy because I don't want to compromise on security at all.

The developers on this project are freelance without expertise in security.

Bilal
  • 3
  • 2
  • Please don't put more than one question into single post. Instead, put your questions to separate posts. – mentallurg Dec 14 '20 at 22:25
  • Thanks @mentallurg I have removed the additional questions. The 1 question is in the title and in bold in the question now – Bilal Dec 14 '20 at 22:56
  • It seems like you're missing a key component here: the client is always untrustworthy and if you don't want the client to have data, then the only option is to not send them data. You seem to be hunting for a way to send data available to the browser but not have it available in the development tools: this is not possible and doesn't even make sense – Conor Mancone Dec 15 '20 at 15:01
  • After all, an attacker can just as easily connect to your API endpoints directly, or send their browser data through a local network proxy that spits out requests/responses in plain text, or do any of a million possible things. If you do not want data being available to the user, then the only choice you have is to not send the data to the user. That is the only possible answer. – Conor Mancone Dec 15 '20 at 15:02

2 Answers2

1

Sensitive Data Exposure

You should ensure that no sensitive data is made available on the frontend simply by loading the page. The site should be designed such that sensitive data must be retrieved from the backend, and only after proving valid authentication/authorization to access such data.

CSRF

CSRF is only really an issue if you are using cookies for authentication; generally, CSRF protection is not needed for API endpoints. Since you haven't mentioned any need to log in or the use of cookies, I don't think this applies here.

Authentication

A hacker will have to know the rules of how to build the token (they won't be able to copy and paste an existing one that they see in the front-end), as the token will be time unique, with any given token only being valid every 5 seconds.

This seems like a problem; an algorithm should remain secure even if an attacker knows how it works (Kerckhoffs's principle); instead, security should rely on a secret key remaining secret.

a hacker can a) figure out how token is encrypted because they can see it being built every time they make a request

If you don't want an attacker to have the token, why do you give it to them in the first place? If it is needed to access the API, this makes little sense since it sounds like it is public already. If the token is needed for administrative API functions, the user/attacker should never be able to get your encryption key in the first place. So maybe the question could use a little clarity on what the API token is actually supposed to protect.

The developers on this project are freelance without an expertise in security.

Developers do not need to be security experts, but must have at least a general understanding of the security implications of the languages/libraries/frameworks they use. I suggest you find developers who have this awareness, or at least hire someone to do a proper audit of your systems before they go live.

multithr3at3d
  • 12,355
  • 3
  • 29
  • 42
  • Hey @miltithr3at3d this is a very helpful answer - I agree with you that security should rely on a secret key remaining secret. I have amended the question to include what exactly needs to being protected (API endpoints from frontend to backend that retrieve user data in a MySQL table and backend scripts for features). The developers are excellent but security is a weakpoint. Your further advice can greatly help us patch it up. Thanks! – Bilal Dec 14 '20 at 23:51
  • @Bilal I see the updates; but who needs API access; everyone or just admins? – multithr3at3d Dec 15 '20 at 03:57
  • @miltithr3at3d Everyone - it's for a public content platform, like YouTube or SO, where content is available for everyone whether they're logged in or not. – Bilal Dec 15 '20 at 11:23
  • @Bilal ok, so why are you trying to restrict the API access if it is meant to be public? – multithr3at3d Dec 15 '20 at 22:05
0

You're both over complicating it and over simplifying it, and you are misunderstanding your use case. You say two things that contradict each other:

  1. It's for a public content platform, like YouTube or SO, where content is available for everyone whether they're logged in or not.
  2. however each user has sensitive information that should remain private.

This is actually quite simple:

Data that should be public is available without authentication. Data that should be private must be behind API endpoints that require authentication.

In short, there you cannot make data available on an endpoint that does not require authentication and also stop people from accessing it. Similarly, you cannot send data to the browser and also stop people from having it. The only way to stop people from having access to data is by never sending it to the browser in the first place.

It sounds like you are hoping to treat your app as trustworthy - aka you want to send data to the app in the browser and trust the app to only show data to users who are allowed to see this. That simply isn't possible. Neither browsers, apps, nor even HTTP work that way. The only way to stop someone from having data is by not sending it in the first place. I'm repeating myself because that is a key point.

Therefore, the only solution is to separate out endpoints: public data gets served over endpoints that do not require authentication, and private data gets sent by endpoints that require authentication and authorization: AKA you verify who the user is, that they are allowed to have access to that data, and then you send it to them. This is the only way it works.

Finally, you mentioned this:

The developers are excellent but security is a weakpoint.

I'm afraid I have to disagree, because this isn't a matter of security: this is a matter of the basic way that the HTTP protocol and HTTP clients work. If your developers don't understand this then they really can't be very good developers. This is like saying that someone is a good cook, they just don't know how to use an oven.

Conor Mancone
  • 29,899
  • 13
  • 91
  • 96