Prevent user from creating a request from another page - authentication

This is technically a csrf attack but this time I am trying to prevent the requests from the user no matter if they are unintentional or not.
I have a cloud storage service where a user can perform CRUD operations on files. I would like to exclusive limit this functionality to my site. So that they could not say, forge a request via postman or cURL and use the service through those methods.

If you send a token with every request and require the token to be returned on the next request, you will make it much more difficult for people to harm your site.
The general approach is to create a token, store it in a session variable, send it to the client, and then test for the token and value on the next request.

Related

CSRF, CORS and my approach to authentication

I've seen many questions about CSRF attacks and GET requests, and I'm trying to work out what I need for my app's authentication system.
My stack is an SPA React app hosted at app.site.com, and an API at api.site.com.
My plan is to do the following.
On load, the React app will call a GET route on the server to get the current user.
This route will check the cookies, look for an httpOnly cookie with a valid token, and if so, send back a loggedin token which will be stored in application memory.
Each subsequent request will then be checked for both tokens in order to succeed.
A potential flaw in this that I can see is as follows:
Could an attacker send a victim to www.other-domain.com, which will trigger a script that calls my /user endpoint? That would send the httpOnly cookie, so the bad site/script will now get back my application memory token, and could then theoretically send other requests. I know I can protect against CORS with this, but is that enough?
I've read that CSRF is a 'write-only' attack, but in this instance I can see that it could be a problem on a GET request.
My questions, then, are:
Is the setup above workable from a security standpoint?
Would using a samesite cookie for the httponly cookie negate the need for the application memory token?
Are there any points in this process that I'm missing?
I've done a lot of research, but would love to hear the thoughts of more experienced engineers. Thank you in advance for any help you can provide.
I've read that CSRF is a 'write-only' attack
In general you're right. CSRF can be used to execute a create or delete action (or any other side effect) on the server - which depending on your server implementation can also happen with a GET request. In some rare cases CSRF can also be used for DoS (Denial-of-Service), for example when you have a very expensive server-side computation in your API, that can be triggered too easy and often via CSRF.
Are there any points in this process that I'm missing?
You would need CORS for your scenario to work (SPA on app.site.com and API on api.site.com). I'd try to avoid using CORS if possible, because 1. it can introduce security problems if configured poorly, 2. it can have a negative impact on performance when the browser runs preflight requests, which effectively will double the roundtrip time, and 3. you introduce tight coupling between your SPA and your API.
And that's where BFF (backend for frontend) comes in handy: You simply use app.site.com/api for your API calls from your SPA, and your app.site.com server will act as a proxy and forward these requests to api.site.com.
Now you don't need CORS at all, and you decoupled your SPA and API, because now you can intercept your API calls at the BFF level and transform the requests made to the API and also transform the responses, aggregate data, combine multiple API requests, etc.

API Authentication for PWA

The Setup
We’re building a PWA (progressive web app). The main components are the app shell (SPA) and the API. The REST API will supply the data needed for the app, while the SPA will handle the rest (as per Google recommendation).
The Problem
Authentication of the end-user seems problematic because the web browser needs to be accounted for. We want the user login to persist through closing down the browser.
We’ve done the research about the possible ways of going about it, however we’d like to ensure that we’re not going in the wrong direction.
Solutions we’ve considered
Session based authentication - the user sends username and password to /accounts/auth and receives a HTTP only cookie with the session ID. The session needs to be stored in a database or Redis. The issue with this option is that cookies are automatically sent by the browser therefore we need a CSRF protection in place. Using the Synchronizer Token Pattern a new token would be generated every time a state changing request has been made e.g. POST. This means that the application needs to supply a CSRF token with every request so that the PWA can send it via AJAX. We determined that it’s not ideal as the user can send multiple post requests in a quick succession making some of them fail and resulting in a bad user experience.
We could also use this method without the CSRF by limiting the CORS policy to same domain and adding a header requirement which technically should stop all CSRF, however we're unsure how secure it would be.
JWT token based authentication - the user sends username and password to /accounts/auth and a new JWT token is issued. The JWT then needs to be stored in localstorage or a cookie. Using localstorage means that JWT is XSS vulnerable and if the token is stolen, an attacker can impersonate the user completely. Using cookies we will still have a CSRF issue to resolve. We considered a double submit cookie method but the CSRF would only refresh every time the JWT is reissued which creates a window for the attacker to find out what the CSRF is. It is not clear which method is best to use.
Session based authentication + JWT token authentication - the user sends username and password to /accounts/auth, a session is created, a HTTP only cookie is set in the browser and a JWT token is sent back to the user. The PWA can authenticate requests with the JWT and whenever the JWT expires the app calls /accounts/auth again to acquire a new one. The /accounts/auth endpoint would still need to be CSRF protected, however the impact of it on usability would be minimised.
There seems to be a large amount of articles claiming that localStorage is insecure and shouldn't be used so why are high profile organisations like Amazon still recommending it? https://github.com/aws/amazon-cognito-auth-js - this SDK uses localStorage to store the token.
You don't need to generate new CSRF token each time a client make a request. It's much easier to use a scheme like token = hash(id + secret + current_day). You only need to update it once a day, or even employ mixed scheme (if the token is invalid today, but is okay for the previous day, the server accepts the operation and returns new token in a predefined header for client to renew it). You may also use the cookie as an id, making the token totally stateless and much easier to check, no need to store them in the database.
Here is how I look at it.
JWT token authentication : with this approach, you can always use a time-bound token with its expiration set to say 2 hours or something?
Or another approach would also be to try and see how you could use some of the approaches the Credentials Management API suggests for example, auto-sign-in of users whenever they come back.
Stuff like 2-step verification with OTPs for instance; for very important features in your web app can be a choice. In this case basic stuff are tied to whichever one time authentication method you have.
Actually, you can also use user-defined pins or short codes (seen a lot in banking apps) to grant access to some features in your web app.
Hope this helps, or sparks some ideation.

Authentication, Authorization and Session Management in Traditional Web Apps and APIs

Correct me if I am wrong: In a traditional web application, the browser automatically appends session information into a request to the server, so the server can know who the request comes from. What exactly is appended actually?
However, in a API based app, this information is not sent automatically, so when developing an API, I must check myself if the request comes from an authenticated user for example? How is this normally done?
HTTP Protocol is stateless by design, each request is done separately and is executed in a separate context.
The idea behind session management is to put requests from the same client in the same context. This is done by issuing an identifier by the server and sending it to the client, then the client would save this identifier and resend it in subsequent requests so the server can identify it.
Cookies
In a typical browser-server case; the browser manages a list of key/value pairs, known as cookies, for each domain:
Cookies can be managed by the server (created/modified/deleted) using the Set-Cookie HTTP response header.
Cookies can be accessed by the server (read) by parsing the Cookie HTTP request header.
Web-targeted programming languages/frameworks provide functions to deal with cookies on a higher level, for example, PHP provides setcookie/$_COOKIE to write/read cookies.
Sessions
Back to sessions, In a typical browser-server case (again), server-side session management takes advantage of client-side cookie management. PHP's session management sets a session id cookie and use it to identify subsequent requests.
Web applications API?
Now back to your question; since you'd be the one responsible for designing the API and documenting it, the implementation would be your decision. You basically have to
give the client an identifier, be it via a Set-Cookie HTTP response header, inside the response body (XML/JSON auth response).
have a mechanism to maintain identifier/client association. for example a database table that associates identifier 00112233445566778899aabbccddeeff with client/user #1337.
have the client resend the identifier sent to it at (1.) in all subsequent requests, be it in an HTTP Cookie request header, a ?sid=00112233445566778899aabbccddeeff param(*).
lookup the received identifier, using the mechanism at (2.), check if a valid authentication, and is authorized to do requested operation, and then proceed with the operation on behalf on the auth'd user.
Of course you can build upon existing infrastructure, you can use PHP's session management (that would take care of 1./2. and the authentication part of 4.) in your app, and require that client-side implementation do cookie management(that would take care of 3.), and then you do the rest of your app logic upon that.
(*) Each approach has cons and pros, for example, using a GET request param is easier to implement, but may have security implications, since GET requests are logged. You should use https for critical (all?) applications.
The session management is server responsibility. When session is created, a session token is generated and sent to the client (and stored in a cookie). After that, in the next requests between client and server, the client sends the token (usually) as an HTTP cookie. All session data is stored on the server, the client only stores the token. For example, to start a session in PHP you just need to:
session_start(); // Will create a cookie named PHPSESSID with the session token
After the session is created you can save data on it. For example, if you want to keep a user logged:
// If username and password match, you can just save the user id on the session
$_SESSION['userID'] = 123;
Now you are able to check whether a user is authenticated or not:
if ($_SESSION['userID'])
echo 'user is authenticated';
else
echo 'user isn't authenticated';
If you want, you can create a session only for an authenticated user:
if (verifyAccountInformation($user,$pass)){ // Check user credentials
// Will create a cookie named PHPSESSID with the session token
session_start();
$_SESSION['userID'] = 123;
}
There are numerous way for authentic users, both for Web applications and APIs. There are couple of standards, or you can write your own custom authorization / and or authentication. I would like to point out difference between authorization and authentication. First, application needs to authenticate user(or api client) that request is coming from. Once user has been authenticated, based on user's identity application needs to determine whatever authenticated user has permission to perform certain application (authorization). For the most of traditional web applications, there is no fine granularity in security model, so once the user is authenticated, it's in most cases also and authorized to perform certain action. However, this two concepts (authentication and authorization) should be as two different logical operations.
Further more, in classical web applications, after user has been authenticated and authorized
(mostly by looking up username/password pair in database), authorization and identity info is written in session storage. Session storage does not have to be server side, as most of the answers above suggest, it could also be stored in cookie on client side, encrypted in most cases. For an example, PHP CodeIgniter framework does this by default. There is number of mechanism for protecting session on client side, and I don't see this way of storing session data any less secure than storing sessionId, which is then looked up in session storage on server-side. Also, storing session client-side is quite convenient in distributed environment, because it eliminates need for designing solution (or using already existing one) for central session management on server side.
Further more, authenticating with simple user-password pair does not have to be in all case done trough custom code which looks up matching user-record in database. There is, for example basic authentication protocol , or digest authentication. On proprietary software like Windows platform, there are also ways of authenticating user trough, for an example,ActiveDirectory
Providing username/password pair is not only way to authenticate, if using HTTPS protocol, you can also consider authentication using digital certificates.
In specific use case, if designing web service, which uses SOAP as protocol, there is also WS-Security extension for SOAP protocol.
With all these said, I would say that answers to following question enter decision procedure for choice of authorization/authentication mechanism for WebApi:
1) What's the targeted audience, is it publicly available, or for registered(paying) members only?
2) Is it run or *NIX, or MS platform
3) What number of users is expected
4) How much sensitive data API deals with (stronger vs weaker authentication mechanisms)
5) Is there any SSO service that you could use
.. and many more.
Hope that this clears things bit, as there are many variables in equation.
If the API based APP is a Client, then the API must have option to retrieve/read the cookies from server response stream and store it. For automatic appending of cookies while preparing request object for same server/url. If it is not available, session id cannot be retrieved.
You are right, well the reason things are 'automatic' in a standard environment is because cookies are preferred over URL propagation to keep things pretty for the users. That said, the browser (client software) manages storing and sending the session cookie along with every request.
In the API world, simple systems often just have authentication credentials passed along with every request (at least in my line of work). Client authors are typically (again in my experience) reluctant to implement cookie storage, and transmission with every request and generally anything more than the bare minimum...
There are plenty of other authentication mechanisms out there for HTTP-based APIs, HTTP basic / digest to name a couple, and of course the ubiquitous o-auth which is designed specifically for these things if I'm not mistaken. No cookies are maintained, credentials are part of every exchange (fairly sure on that).
The other thing to consider is what you're going to do w/ the session on the server in an API. The session on a website provides storage for the current user, and typically stores small amounts of data to take load off the db from page to page. In an API context this is less of a need as things are more-or-less stateless, speaking generally of course; it really depends what the service is doing.
I would suggest you send some kind of token with each request.
Dependent on the server and service those can be a JSESSIONID parameter in your GET/POST request or something mature like SAML in SOAP over HTTP in your Web Service request.

Password protecting a REST service?

After creating a basic REST service, I've have come to the point where it would be appropriate to add some sort of password protection, as I need to verify that my users are both properly logged and have sufficient permissions to execute whatever action they are going to.
The REST service will mainly be accessed from a Javascript-heavy frontend and with that in mind, I have come up with the two following alternatives to solve this:
Make users login by first sending credentials to a /login page with POST. The page sets a session cookie wherein the user is
marked as logged in, along with the permission level. On each
following request, I verify that the user is logged in and his/her
permission level. When the session expires, automatically or
manually (logout, the user will have to re-logon).
Temporarily save the credentials hashed locally and send the users credentials along every single request made by the user to verify the credentials & permissions backend on a per-request basis.
Are there more ways to solve this and is there something else that I should be concerned with?
I'm currently developing a REST API along with a client (written in javascript), below I'll try to explain the methods used to protect the API against unauthorized access.
Make your REST API to require a Auth-Key header upon every request to the API, besides /api/authenticate.
/api/authenticate will take a username and a password (sent using POST), and return user information along side with the Auth-Key.
This Auth-Key is randomly generated after a call to /api/authenticate and stored in the backend users table with the specific user entry, a md5 hash of the remote ip + the user agent provided by the client.
On every request the value of Auth-Key, and the md5 sum mentioned, is searched for in users . If a valid user is found that has been active during the past N minutes the user will be granted access, if not: http return code 401.
In the REST client, first get the Auth-Key by posting to /api/authenticate, then store this value in a variable and send in on every future request.
If you want to stay true to the definition of a REST service then it should be stateless and not store any login (or other context specific) data on the server: http://en.wikipedia.org/wiki/Representational_state_transfer#Constraints
Your 2nd approach would fit this model
First decide what it is that you're protecting against:
Authentication? (Knowing who is requesting your service?)
Authorization? (Whether a given person can properly request a given service or not?)
I recommend that you provide hashed keys for your service. That way you can manage the key issue separately from the services. Or a client key and a secret, Amazon does this.
It is always easier for the client if you have a stateless protocol. And send everything through the parameters, cookies are a bother for the client too.
Remember that it is in your interest to make it as easy as possible for potential developers to use your service. A super secure service that no one uses is boring.
You can let clients choose the security level by giving them the choice of HTTP or SSL/HTTP endpoints to connect to. Client choice is a good thing.
Make users login by first sending credentials to a /login page with POST. The page sets a session cookie wherein the user is marked
as logged in, along with the permission level. On each following
request, I verify that the user is logged in and his/her permission
level. When the session expires, automatically or manually (logout,
the user will have to re-logon).
Temporarily save the credentials hashed locally and send the users credentials along every single request made by the user to verify the
credentials & permissions backend on a per-request basis.
Your first approach does not meat the statelessness constraint of REST. You cannot maintain client sessions on server side. This constraint makes REST highly scalable...
Your second solution is appropriate. The simplest way to use HTTP basic auth. You don't have to hash the password on client side. What you need is an encrypted connection. On server side you can have an [username, password] -> [identity, permissions] cache, so this solution is much faster and superior in every other way than having server side sessions.
By 3rd party (non-trusted) clients the authentication is more complex, I guess you don't need that part.
I'm no security-expert. I use the RESTful Play!-webframework and they do the following things to authenticate users.
The cookie is protected against manipulation. It is signed with a long secret key and is checked for each request. Just hashing it is not enough!
They recommend to set unique information the identify the user in the cookie. As the server should be the only one to manipulate the cookie, that's enough.
Don't put the password as credential in the cookie. If someone sniffs the cookie, not only the session can be hijacked, but also the complete account or even worse, other accounts with the same credentials.
If you want to protect the cookie against hijacking using https.

REST and authentication variants

I am currently working on a REST library for .net, and I would like to hear some opinions about an open point I have: REST and authentication.
Here is an example of an RESTful interface used with the library:
[RestRoot("/user")]
public interface IUserInterface
{
[RestPut("/")]
void Add(User user);
[RestGet("/")]
int[] List();
[RestGet("/get/{id}")]
User Get(int id);
[RestDelete("/delete/{id}")]
void Delete(int id);
}
The server code then just implements the interface and the clients can obtain the same interface through a factory. Or if the client is not using the library a standard HTTP request also works.
I know that there are the major ways of either using HTTP Basic Auth or sending a token to requests requiring authenticated users.
The first method (HTTP Basic Auth), has the following issues (partly web browser specific):
The password is transmitted with every request - even with SSL this has some kind of "bad feeling".
Since the password is transmitted with a request header, it would be easy for an local attacker to look at the transmitted headers to gain the password.
The password is available in the browsers memory.
No standard way to expire user "sessions".
Login with a browser interrupts the look and feel of a page.
The issues for the second method are more focused on implementation and library use:
Each request URI which needs authentication must have a parameter for the token, which is just very repetitive.
There is a lot more code to write if each method implementation needs to check if a token is valid.
The interface will become less specific e.g. [RestGet("/get/{id}")] vs. [RestGet("/get/{id}/{token}")].
Where to put the token: at the end of the URI? after the root? somewhere else?
My idea was to pass the token as parameter to the URL like http:/server/user/get/1234?token=token_id.
Another possibility would be to send the parameter as an HTTP header, but this would complicate usage with plain HTTP clients I guess.
The token would get passed back to the client as a custom HTTP header ("X-Session-Id") on each request.
This then could be completely abstracted from the interface, and any implementation needing authentication could just ask which user the token (if given) belongs to.
Do you think this would violate REST too much or do you have any better ideas?
I tend to believe that authentication details belong in the header, not the URI. If you rely on a token being placed on the URI, then every URI in your application will need to be encoded to include the token. It would also negatively impact caching. Resources with a token that is constantly changing will no longer be able to be cached. Resource related information belongs in the URI, not application related data such as credentials.
It seems you must be targeting web browsers as a client? If so you could investigate using HTTP Digest access authentication or issuing clients their own SSL certificates to uniquely identify and authenticate them. Also, I don't think that session cookies are necessarily a bad thing. Especially when having to deal with a browser. As long as you isolate the cookie handling code and make the rest of the application not rely on it you would be fine. The key is only store the user's identity in the session, nothing else. Do not abuse server side session state.
If you are targeting clients other than the browser then there are a number of approaches you can take. I've had luck with using Amazon's S3 Authentication mechanism.
This is all very subjective of course. Purity and following REST to the letter can sometimes be impractical. As long as you minimize and isolate such behavior, the core of your application can still be RESTful. I highly recommend RESTful Web Services as a great source of REST information and approaches.
I agree with workmad3, if session life time needs to be maintained you should create a session resource. Post on that resource with user credentials (either basic authentication or credentials in the body content) will return unique session id. Delete on /session/{id} will log out the user.
If you want to control the session expiry time. When creating new session (post on session resource) the server will set a cookie on the response (using standard set-cookie header).
The cookie will contain expiry time. The cookie string should be encrypted on the server, so only the server can open that cookie.
Every consequent request to the server will send the session cookie in the cookie header. (it will be done automatically for you if your client is a browser). The server needs to "renew" the cookie for every request, i.e. create new cookie with new expiry time (extend session's timeout).
Remember to clear the cookie when the user calls delete on the session resource.
If you want your application to be more secured you can store the client IP in the cookie itself, so when a request arrives the server can validate that it was sent from the "original" client. But remember that this solution can be problematic when proxies are involved, because the server might "see" all the requests as coming from the same client.
The rest authentication I've seen treats the sessions as a REST resource for creation, destruction etc. and then the session ID is passed to and fro. The ones I've seen tend to use the session cookie for this as it's the only way to secure it really. If you pass the session id in the URL, you don't have any way of really authenticating it came from the correct client.
Authentication is a tricky problem with REST though, as it requires some form of state to be kept outside the URL which infringes upon REST principles of the URL being all that is required to represent state.