How to associate static files with user in Express? - file

I want to associate static files with particular users in express and place some kind of authentication so that a particular set of files can only be seen by the user they are associated with.
I am using multer to upload files.
My middleware serves all files requested.
app.use(express.static(path.join(__dirname, "public")));
In my SQL database I'm storing the path of the image along with user_id. Now when a resource is requested I want to make sure whether the requesting user owns it otherwise reject the request.

You can add a middleware function right before it and have that middleware check to see if the request is permitted - something like this.
app.use(checkUser, express.static(path.join(__dirname, "public")));
checkUser would then need to be a middleware function that checks to see if the user is allowed to request this particular URL. If not, then it returns an error and does NOT call next() so express.static() never sees the request. If the user is allowed, then the middleware calls next() and express.static() will see if it can serve that URL.

Related

Client Side Rendering and API Security [duplicate]

I'm developing the restful web app that using some popular web framework on the backend, say (rails, sinatra, flask, express.js). Ideally, I want to develop client side with Backbone.js. How do I let only my javascript client side interact with those API calls? I don't want those API calls to be public and be called by curl or simply by entering the link on browser.
As a first principle, if your API is consumed by your JS client, you have to assume, that it is public: A simple JS debugger puts an attacker into a position, where he can send a byte-for-byte identical request from a tool of his choice.
That said, if I read your question correctly, this is not, what you want to avoid: What you really don't want to happen is, that your API is consumed (on a regular basis) without your JS client being involved. Here are some ideas on how to if not enforce, then at least encourage using your client:
I am sure, your API has some sort of authentication field (e.g. Hash computed on the client). If not, take a look at This SO question. Make sure you use a salt (or even API key) that is given to your JS client on a session basis (a.o.t. hardcoded). This way, an unauthorized consumer of your API is forced into much more work.
On loading the JS client, remember some HTTP headers (user agent comes to mind) and the IP address and ask for reauthentication if they change, employing blacklists for the usual suspects. This forces an attacker to do his homework more thoroughly again.
On the server side, remember the last few API calls, and before allowing another one, check if business logic allows for the new one right now: This denies an attacker the ability to concentrate many of his sessions into one session with your server: In combination with the other measures, this will make an abuser easy detectable.
I might not have said that with the necessary clarity: I consider it impossible to make it completely impossible for an abuser to consume your service, but you can make it so hard, it might not be worth the hassle.
You should implement some sort of authentication system. One good way to handle this is to define some expected header variables. For example, you can have an auth/login API call that returns a session token. Subsequent calls to your API will expect a session token to be set in an HTTP header variable with a specific name like 'your-api-token'.
Alternatively many systems create access tokens or keys that are expected (like youtube, facebook or twitter) using some sort of api account system. In those cases, your client would have to store these in some manner in the client.
Then it's simply a matter of adding a check for the session into your REST framework and throwing an exception. If at all possible the status code (to be restful) would be a 401 error.
There's an open standard now called "JSON Web Token",
see https://jwt.io/ & https://en.wikipedia.org/wiki/JSON_Web_Token
JSON Web Token (JWT) is a JSON-based open standard (RFC 7519) for
creating tokens that assert some number of claims. For example, a
server could generate a token that has the claim "logged in as admin"
and provide that to a client. The client could then use that token to
prove that they are logged in as admin. The tokens are signed by the
server's key, so the server is able to verify that the token is
legitimate. The tokens are designed to be compact, URL-safe and usable
especially in web browser single sign-on (SSO) context. JWT claims can
be typically used to pass identity of authenticated users between an
identity provider and a service provider, or any other type of claims
as required by business processes.[1][2] The tokens can also be
authenticated and encrypted.[3][4]
Set a SESSION var on the server when the client first loads your index.html (or backbone.js etc.)
Check this var on the server-side on every API call.
P.S. this is not a "security" solution!!! This is just to ease the load on your server so people don't abuse it or "hotlink" your API from other websites and apps.
Excuse me #MarkAmery and Eugene, but that is incorrect.
Your js+html (client) app running in the browser CAN be set up to exclude unauthorized direct calls to the API as follows:
First step: Set up the API to require authentication. The client must first authenticate itself via the server (or some other security server) for example asking the human user to provide the correct password.
Before authentication the calls to the API are not accepted.
During authentication a "token" is returned.
After authentication only API calls with the authentication "token" will be accepted.
Of course at this stage only authorized users who have the password can access the API, although if they are programmers debugging the app, they can access it directly for testing purposes.
Second step: Now set up an extra security API, that is to be called within a short limit of time after the client js+html app was initially requested from the server. This "callback" will tell the server that the client was downloaded successfully. Restrict your REST API calls to work only if the client was requested recently and successfully.
Now in order to use your API they must first download the client and actually run it in a browser. Only after successfully receiving the callback, and then user entry within a short frame of time, will the API accept calls.
So you do not have to worry that this may be an unauthorized user without credentials.
(The title of the question, 'How do I secure REST API calls', and from most of what you say, that is your major concern, and not the literal question of HOW your API is called, but rather BY WHOM, correct?)
Here's what I do:
Secure the API with an HTTP Header with calls such as X-APITOKEN:
Use session variables in PHP. Have a login system in place and save the user token in session variables.
Call JS code with Ajax to PHP and use the session variable with curl to call the API. That way, if the session variable is not set, it won't call and the PHP code contains the Access Token to the API.

How do I hide an API key in Create React App?

I made a weather app in Create React App (create-react-app). How do I hide the API key so that I can commit to GitHub?
Right now, the key is in App.js:
const API_KEY = "123456";
Unfortunately, keeping any key in your React client, even if you are using gitignore and an .env file, is not secure. As pointed out by Claudiu Creanga, React environment variables are embedded in the build and are publicly accessible.
You should really only save API keys or secrets in your backend such as Node.js or Express.js. You can have your client send a request to your backend API, which can then make the actual API call with the API key and send the data back to your client.
Disclaimer
WARNING: Do not store any secrets (such as private API keys) in your
React app!
Environment variables are embedded into the build, meaning anyone can
view them by inspecting your app's files.
The following answer provides a correct way to store non-secret data in environment variables. Remember that secret data is accessible through developer tools, making it unsafe to store as environment variables. If you want to store some secret data then storing in the backend is the better option and if the client wants to access secret data, it can be accessed by making a request to the server. (Refer to Antonia's answer for more details on storing secret data.)
As it turns out, create-react-app has some built-in functionality to help you with that. Thank you George Karametas for this insight. To access that functionality, you need to:
1. Create a file called .env in the root of your project's directory.
- your_project_folder
- node_modules
- public
- src
- .env <-- create it here
- .gitignore
- package-lock.json
- package.json
2. Inside the .env file, prepend REACT_APP_ to your API key name of choice and assign it.
The create-react-app tool uses REACT_APP_ to identify these variables. If you don't start your API key name with it, create-react-app won't see it.
// .env
REACT_APP_API_KEY=your_api_key <-- yes
API_KEY=your_api_key <-- no
// Example (from 이준형's response):
REACT_APP_WEATHER_API_KEY=123456
3. Add the .env file to your .gitignore file.
After you add the line below, save the .gitignore file and do a git status to make sure your .env file does not appear as a new file in git.
// .gitignore
# api keys
.env <-- add this line
# dependencies
/node_modules
...
4. Access the API key via the process.env object.
To check that you can access your API key, go to your App.js file and add a console.log at the top below the require statements. After saving the file and reloading the page, if the console log does not show your API key, try restarting the react server. Be sure to remove the console log line before committing your code.
// src/App.js
import React, { Component } from 'react';
import './App.css';
console.log(process.env.REACT_APP_WEATHER_API_KEY)
class App extends Component {
...
Warning
Unless you're making tutorial applications, don't put secrets such as API keys in client-side source code (e.g., a React app). From Create React App's documentation:
WARNING: Do not store any secrets (such as private API keys) in your
React app!
Environment variables are embedded into the build, meaning anyone can
view them by inspecting your app's files.
First, create an .env file in the root of your project, i.e., where you would run react-scripts start (or yarn start) outside of your source folder.
Then, add
REACT_APP_WEATHER_API_KEY=123456
Before commit, you should exclude this .env file, so find the .gitignore file and add .env.
The name of the variable needs to begin with REACT_APP_ which protects you from accidentally including secrets with your build.
Don't forget to add .env in the .gitignore file.
To use the environment variables in your code:
const API_KEY = process.env.REACT_APP_WEATHER_API_KEY;
In order to read environment variables after having added them to .env, restart your server.
From the React documentation:
WARNING: Do not store any secrets (such as private API keys) in your React app!
Environment variables are embedded into the build, meaning anyone can
view them by inspecting your app's files.
Although the question has already been answered by Antonia Blair, I would like to through some more light on some basic rules.
1: Most of the answers are suggesting to make use of the .env file. I would like to make it clear for once and all that .env is not here to add any security layer. The .env as the name depicts is only here to set up an environment at build time. e.g. by using the environment variables you set some global values at build time and can access these values in your application at runtime.
2: React is simply a framework running your JavaScript code in the client browser. So the client has complete access to the JavaScript (React) code. Nothing is secure on the client-side. So never think of making something secure or hidden from the client by just keeping all your code client-side. Whenever you need to hide something from the client, there is something server-side which you need to incorporate. Only the server-side code is secure from the client-side.
3: So what you do is, you will keep your secure keys on the server-side.
Suppose the purpose of your secure keys is to make a cookie for your client. so the client needs the cookie not the secure keys, right? So the client-side makes a request to the server for a cookie, the server makes the cookie by using the secure keys and returns the cookie to the client. After all the client is only here to eat the cookie and not to know how do we make a cookie right?
4: So the thumb rule is that wherever you have some confidential data, you will keep it on the server. The server will use this confidential data and return the result data to be exposed to the client.
A user has asked for a coding example, so I have put up a real-time scenario which I have handled using the above described technique.
Here is my use case:
I have a React app which submits a public form to non public API.
The non public API is Harvest API hosted by:
https://www.greenhouse.io/
This API requires an authentication header for making requests with it. I have subscribed with the API owner and received a secret token from them which I can use with my requests to get access to their API
Af course, I want to keep my token personal and do not expose it to public users
I have used the Axios client to communicate with the API
I have two ways to perform the above described scenario:
The Incorrect Method
I am making requests to the API directly from my React application
Let’s say below is the API endpoint which I want to hit
apiURL = https://boardsapi.greenhouse.io/v1/boards/xyz/jobs/" + jobId + ""
The above API endpoint requires an authorization header, and I will provide my secret token in it.
const config = {
headers: {
"Authorization": "Basic ####MySecretCode#####",
} };
Suppose I want to post some form data with this request
let formData = MyFormData
I can now send my request using the Axios client like below
let result = await axios.post(apiURL, formData, config);
Using the above technique, I can successfully post my form data to the Harvest API.
But like I said, that it's an incorrect way to communicate with this API. Because I have exposed my secret token on the client side.
The Correct Way
I built an API on Node.js and hosted it publicly.
Suppose I want to post some form data to the Harvest API
let formData = MyFormData
I am not going to hit the Harvest API directly from my client application. And instead I have exposed and endpoint in my middleware API to handle this.
Let’s say the below is the endpoint URL of my middleware API which I want to hit
apiURL = https://proxy-server/apply
The above API endpoint does not requires an authorization header. So I can send a post requests using the Axios client like below:
let result = await axios.post(apiURL, formData);
The difference is clear. I have not supplied the secret token this time in my request. Because this is not a direct request to the Harvest API and instead it's a request to a middle-ware API which is developed and hosted by me.
I receive this request in my middle-ware API, add my secret token with it and forward it to the Harvest API. The response from Harvest API is returned to our middle_ware API and hence forward back to our React client application.
The secret token now resides on my server-side API and safe from external users.
Here's what worked for me:
I created the .env file in the root folder.
Within that folder I added my key:
REACT_APP_API_KEY_YT = "key"
// I added 'YT' for YouTube which is where my API key is from
Then I went to .gitignore. Or create a .gitignore file in your root directory if you don't have it. Within .gitignore, I added .env
# API key
.env
Then I went back to the root of my App js file. For me, that was index.js. For others, it is probably App.js.
There I created a const API_KEY
const API_KEY =`${process.env.REACT_APP_API_KEY_YT}`
I checked if it was working by console logging it.
console.log("API", API_KEY)
I was getting undefined.
I stopped the server (Ctrl + C) and restarted the server.
Afterwards I was able to see the key.
Here is an example of finding the API key in code even when you attempt to hide it in an environment variable.
I built a very simple app using the NewsAPI, which required me to register for an API key. Here is my fetch to the NewsAPI endpoint using the API key as an environment variable.
fetch(`https://newsapi.org/v2/top-headlines?q=${keyword}&apiKey=${process.env.REACT_APP_API_KEY}`)
.then(res => res.json())
.then(
(result) => {
setIsLoaded(true);
setArticles(result.articles);
})
However, when I inspected the network request with Chrome dev tools, you will be able to see the actual value of the API key. I hope this helps folks see how somebody could find an API key on the client even if you store it as an environment variable.
How one could hide an API key:
You could make the HTTP request from your server side logic, so you can safely hide an API key in the .env file. In the below example I created an enpoint to /top-headlines/:searchTerm. Once a request to that endpoint is received, then I send the Axios request to the news API using the "NEWS_API_KEY" environment variable which is stored in my .env file.
route.get("/top-headlines/:searchTerm", async (req, res) => {
const { searchTerm } = req.params;
try {
const articlesResponse = await axios.get(
`https://newsapi.org/v2/top-headlines?q=${searchTerm}&apiKey=${process.env.NEWS_API_KEY}`
);
const articlesData = articlesResponse.data;
res.send(articlesData);
} catch (error) {
console.log(error);
}
});
If you use the API key for local development purposes, put it under the .env.development file and Git ignore it. Credentials in the .env file will be picked up by the build process, which will expose the data in production.
For details, see What other .env files can be used?
Be advised! If you put any credentials in a React client, they are not secure, even if you are using gitignore and an .env file. Still they are not secure.
You should really only save API keys or secrets in your backend, such as Node.js or Express.js. Use a proxy, send the request from the front end to the backend and then the backend will make a request for fetching data to front end.
If you are in production, then you cannot use environment variable directly there for frontend (React). You need to follow the instructions on How to implement runtime environment variables with create-react-app, Docker, and Nginx in order to achieve this goal if you want to access environment variables in production.
The secure key/secret should never be sent to the client side. Say, you want to download a file from S3 down on the client machine via your app (running in a browser).
Make a call to the server to obtain a ephemeral token (which expires with time)
the server (which has the secret and everything) makes the token and sends it back
the client uses the token to access S3
The token itself is not a secret and it's useless once it expires.
Creating a .env file is helpful as stated in previous answers. But one point to notice here is that:
If you are using API_KEY in your URL as state like this,
this.state = {
url:`http://newsapi.org/v2/everything&apiKey=${process.env.REACT_APP_API_KEY}`
}
then it will be visible in React developer tool.
Instead, you can put your API_KEY directly at the location of fetch. For example,
fetch(`http://newsapi.org/v2/everything?&apiKey=${process.env.REACT_APP_API_KEY}`)

REST API in MEAN stack, passed id vs id from session

I'm building a web app using MEAN stack.
While building the REST API I see a lot of examples with the following endpoint
/api/contacts/:id
for GET, PUT and DELETE methods.
I did something different, I enabled session in the Express framework and now I can see the user document id (for mongoDB) under req.session.req.payload._id when I do a HTTP request which enables me to access the document.
That why I also don't need to expose the user document id in the URL when I do
a HTTP request.
My question is which method is better and safer to use?
Also, how can I get the user id in Angular to pass to the HTTP request in case I don't use sessions.
And a final one... I also use JWT as middle-ware before calling the function which updates the DB. This gives me some sense of security but wouldn't it be possible for a user with the correct token to do HTTP requests with different ids and by that getting, updating and deleting other users data?
This won't be possible with the current method I'm using (sessions)
When you need to pass the user ID to the endpoints then your client code will need to know that and it's the backend that needs to provide it somehow - either as part of the returned toked or usually as part of the response to a successful login request. The client can store it in a cookie or a local storage to use later.
It is not very practical, though, to have to provide the ID of the user in every route like:
/api/contacts/:id
When your users need to be able to access other users contacts then you may need to use the ID in the route and you may not want to have another set of routes for a situation when the user wants to manipulate his or her own contacts.
What I've seen sometimes done in practice in situations like this is to use a special value for the ID like "me" and have your backend translate all routes like this:
/api/contacts/me
to:
/api/contacts/:id
where :id is the ID of the user who made the request, taken from the session. This can be done with a middleware to substitute the value for all routes at once, and then your normal controllers could use it like it was provided in the route to begin with.

Secure REST API without user authentification (no credentials)

I've been struggling for 2 days now on how to secure a REST API without user authentification.
What does it mean ?
In my AngularJS application I identify an user by sending a GET request to an existing service (companydomain/userinfo) which I must use. I'm not sure how this work since I am not the author of this piece of code but the point is that I get the information about the user in the response as JSON (active directory name, phone in the company...).
This is all I have to identify an user.
What I did
Now, I found a lot of resources talking about OAuth, unique token, etc. but nothing seems to match with my issue. I implemented a token system but it's plain useless since I can't be sure of the authenticity of the requester.
User open the application. Application ask the service about the information related to the user. companydomain/userinfo
Application request a token to the server (nodejs & express), based on the information returned. /api/token/get/{user_info}
Server generates an unique token and store it in memory with expiration date and owner. The server also check in the table "authorized users" if the user exists (based on the active directory name), if not a new entry is added to it.
Application send the token along each request to the API. /api/entry/delete/{entry_id}
I think you see what is wrong here, an attacker could easily make a corrupted request to the API to get a legit token. So my question is :
How can I manage to secure my API since users don't use credentials to authentify ?
I hope my question is clear enough and at this point I am not even sure I can get around this issue without adding a credentials system.
You might want to look at Passport. It is a platform that allows you to easily add authentication to your application. There are many authentication strategies available. I am using Passport in a Node.js application implementing my own hmac strategy.
To authenticate, the client request includes an API ID to identify who the caller is and also includes an signature of a specified part of the message that includes things like the HTTP method, the API ID, a date value and some other header values, like maybe content-type. What data to include in the string to sign is up to you in your implementation, but the client and server must create and sign the same strings for the authentication to work. The signature is created by doing an hmac hash of the string using a shared secret.
On the server side, you use the API ID to retrieve the shared secret (possibly from a database or the filesystem) and perform the same hash on the request. If the hmac values match then you've authenticated the request. To prevent playback attacks, the date is included in the signed part of the request and must be within a certain window of the server's current time. For example, you might reject the request if the timestamp is more than 30 seconds old.
To enable a new user of your API, you generate a new API ID and shared secret. You give both of those to your API user and you store them for look up in your database or filesystem. The user must sign the requests with the shared secret and include the ID in the request.
The Hawk strategy provides much of this functionality, but we decided to roll our own hmac strategy.
Because you say that the user info endpoint returns active directory name, I assume you're on the Windows platform.
If so, why not use Windows integrated authentication (Kerberos) to authenticate your users without asking them for credentials? This will only work within your active directory domain, but is completely transparent to your service.
You can still call the user info endpoint and verify that the info it returns is for the same user that is calling your REST service.
If you need to call services that do not support Windows integrated auth, you could generate a security token (sign it to guarantee integrity) and make the other services trust this token.

How to securely set authorization header using angularJs?

It is common to authenticate to web services using an authorization header which contains a secret token. And since the security of this mechanism depends on the token to be secret care should be taken that this token is not leaked.
There are countless tutorials on the web which explains how such an authorization header can be set using angular and least the ones that I have actually read use an $http interceptor and now one discusses that the token is not leaked.
There are some public and some private APIs out there which can be talked to cross domain thanks to CORS. And obviously I do not want to send my internal authorization tokens on any of those requests.
Some other techniques come to mind such as setting the token manually only on each and every request, but that means lots of duplicate code. The $http server could be wrapped in an $authenticatedHttp service so that it is always appearent from the object used whether it is the authenticated service or the normal one. However the $http service has so many methods to be wrapped.
Is there a better solution?
UPDATE
From the answers I have the impression that my question was not understood. I try it with a more concrete example:
I have a private web page. People have to login with username/password and let's say for simplicity's sake that we use HTTP basic auth, so username/password are bas64 encoded and are transmitted on every request in the HTTP header "Authorization". So far there is no problem.
But there is this great&free weather widget. I can retrieve the current weather information in JSON format from https://myWhateverWeatherService.tld/weather.json. After the login to my private web service I also retrieve the weather information (CORS allows me to do this).
The problem is that even though myWhateverWeatherService.tld does not require any authentication at all, angular's $http service will still append the Authorization header. And I don't trust the guys at myWhateverWeatherService.tld. Maybe they just set up the service so they can steal Authorization token and do lot's of nasty stuff with them.
I need some reliable way to deal with that. I already thought about checking the url with some regex in the interceptor. This is possible, but it is also not to difficult to forget about a certain case that my regex will miss.
The token is always sent through the wire, I guess that is the most vulnerable part of it.
Since the token must always be present on the http header itself, the only way to make the request more secure is to encrypt the whole request, and for that you should use SSL.
If you are concerned about the safety of storing the token on the client machine, you can keep it only on the browser´s memory, without persisting it on a localstorage or something like that. So every time the user closes the browser and open it again, s/he must log in.

Resources