Is it a good praxis to secure an webservice endpoint with a simple token string? - web-services

I have a web application where the regular user login is handled via SSO.(This prevents me from creating a service user)
In this application I have some web service endpoints that are not in the scope of any user. They will be triggered by another application and do some stuff.
Is the following the right way to do.
A token string is created by hand(because of simplicity)
The token string is stored in the environment variables of the system that provides the webservice endpoint as well as in the system that calls those endpoints.
On every call a simple equality check is proceeded - if the token is not present, the endpoint returns a 401.
Is my approach to simple?
I have not found much on this topic - my approach comes from the moodle-webservice handling, where you generate a webservice token in moodle and place it aswell in the application that calls the webservice.

For a basic application with no high security requirements, this might be ok.
A few things you could do (all of which will increase complexity and/or cost):
The service could store a proper password hash (like bcrypt, pbkdf2 or argon2) instead of the actual password. This would help, because if it is compromised, the actual key would not be lost, the attacker could still not easily call the service. (But it's already compromised, and this is not like a user password that would be reused, so it depends your choices and threat model.)
You could store this secret in a proper vault like AWS Secrets Manager or Hashicorp Vault or similar. This would enable you to control access to the key in one place, and audit key usage (maybe alert on attempts and so on). Access to the vault would still have to be managed, but that's easy via roles on AWS for example, where instances with the right role can access the secret but others cannot.

Related

Allowing temporary access to DynamoDB

I have a client app that connects to an Elastic Beanstalk server app. Some of my users need to register. But when the registration form loads it needs to get some data from DynamoDB so the user can choose between a few options.
The problem is that I set up my server in a way that any request to the server that is not authenticated (no auth tokens previously obtained by the client app from Cognito) gets denied. Of course, if a person is going to register they are not authenticated, which means they do not have access to the information from DynamoDB they need to register. It is only a couple of pieces of information I need, so it is very frustrating.
What I have thought about how to solve this:
Putting a long string of characters in the client app that gets sent to the server when a request is made for ONLY the couple of pieces of information I need. The server would also have that same string stored somewhere and would then compare them. If they match, then it returns the info requested. As I said, this would be done only for the 2 pieces of info I need, everything else would still be secure.
Leave the two routes public in my API that lead to the pieces of info I need (I know, it is a bad idea).
What would be the best way to go about this?
Assuming you're using cognito there is also a concept of an anonymous guest user which can have its own role assigned.
You can treat the anonymous guest user like a regular cognito user (it can have a role assigned), however you would scope its permissions down to the minimum it requires to perform these operations.
Alternatively use option 2, the API could call a Lambda that would return the necessary information simply reading the data. You would possibly want to look at caching the results as well to avoid your API Gateway endpoint being abused.

How to check for Cognito permissions in API Gateway

Trying to understand how to use Cognito and API Gateway to secure an API.
Here is what I understand so far from AWS documentation and the Cognito user interface:
Clients
www-public - public facing website
www-admin - administrators website
Resource Servers
Prices - for this simple example the API will provide secured access to this resource.
Scopes
prices.read
prices.write
Again, very simple permissions on the API. Public www users can read prices, administrators can write them.
API Gateway
GET /prices - accessible to authenticated users that can read prices.
POST /prices - only accessible to administrators
Users
Administrators - can update prices via the POST method.
Non-administrators - cannot update prices.
Based on this...
Each client will request the scopes it is interested in. So for the public www site it will request prices.read and for the administration site both prices.read and prices.write.
The API Gateway will use two Cognito Authorisers, one for each HTTP Verb. So the GET method must check the user can read prices and the POST method that they can write prices.
The bit I don't see is how to put all of this together. I can make the clients request scopes but how do they now connect to user permissions?
When the token is generated, where is the functionality that says "Ok, you requested these scopes, now I'm going to check if this user has this permission and give you the right token?"
I understand that scopes ultimately related to the claims that will be returned in the token.For example, requesting the profile scope means that the token will contain certain claims e.g. email, surname etc.
I think based on this that my permissions will ultimately end up being claims that are returned when specific scopes are asked for. The fact that the two clients differ in what they request means that the prices write claim an never be returned to the public www client. It would never issue a token if the prices.write claim was requested.
What I can't see is where this fits in Cognito. There is the option to put users into groups but that is pretty much it. Likewise, there is nothing (that I could see) to relate scopes to claims.
I'm coming from a .Net and Identity Server background. Certainly in the last version of Identity Server I looked at there was a handler method where you would work out which claims to put into a token. I guess this would map into one of the custom handler lambda functions in Cognito. From there this would need to query Cognito and work out what claims to issue?
The final piece of the puzzle is how the API Gateway checks the claims. Can this be done in API Gateway or does the token need to be inspected in the Lambda function I will write to handle the API Gateway request?
Certainly using Identity Server and .Net there was a client library you would use in the API to inspect the claims and redact permissions accordingly. Guessing there is something similar in a Node JS Lambda function?
A few assumptions there as I'm basically in the dark. I think the basics are there but not sure how to connect everything together.
Hoping someone has figured this out.

How to implement API security for local and remote requests?

I have setup an web-based API to allow a remote app to GET/POST data. Every API call is authenticated with a User ID and Password that is encrypted with a secret key known only to the remote app and the website. This authentication not only ensures that the user can access the API, but also allows me to implement security features based on the user's profile (i.e. User A can see items A & B, but not item C).
I would like my server-side website pages to be able to call the same API methods remotely via AJAX calls, but, something just doesn't seem right about storing encrypted passwords in the code, and, my website implements a "Login As" feature, which will not allow me to set the encrypted password, since the passwords are not stored in plain text.
What is a good way to implement API security for both remote and "local" calls that doesn't require encrypting the user's password?
You should not be storing usernames and passwords in server side code. Sooner or later someone will lay eyes on your code and your data will be vulnerable.
But you should also not be storing secrets (key) in client side code. You should not assume your client can be trusted to keep that secret.
Giving user A access to item A and B, but not C is called authorization and depends on you knowing who calls your API (authentication).
You should probably look into a authentication protocol like OpenID Connect and an authorization protocol like OAuth 2.0.
Also see my answer to this question.

End user authentication for RESTful web services

I have an internal-facing RESTful web service. There are various client applications using the service, and the client apps themselves have end users. The web service needs to authorize requests based on the end user identities.
The question: What are the typical options for authenticating the end user here? That is, I want to authenticate the user, not the client application. (I don't mind if authenticating the client application is part of the scheme, but ultimately I need to know that the end user is who I think he or she is.)
One possible scheme, for example, would be to have per-client system accounts, and then have the client simply assert the user's identity (e.g. in an HTTP request header, say). So we authenticate the client application and delegate user authentication to the client. I don't think this is a very strong scheme, though, because it depends too much on keeping the system account credentials secret. I have seen too many examples of people e-mailing system account credentials around to put much faith in this sort of approach.
Another approach might be to have the client app, upon user login, use the user's credentials to get a token from the API, and then use that token for subsequent API requests. That way the authentication is user-specific without requiring the client app to hang onto the username/password credentials.
Anyway I'd like to have a better sense for the range of options I should be considering here.
The problem that you describe with "delegated authentication" is a real one. It means that a "client application" using it's credentials has access to the whole breadth of user data. This access can be used maliciously (for example a "semi-trusted" app harvesting api data) or negligently (for example an app accidentally exposing a Direct Object Reference Vulnerability - https://www.owasp.org/index.php/Top_10_2010-A4-Insecure_Direct_Object_References)
Probably the most prevalent "token based" scheme is OAuth2 (http://oauth.net/2/), and the precursor, OAuth, which many sites choose to continue to use.
OAuth2 has a number of roles:
resource owner (the user in your case)
resource server (your api)
client (the apps you talk about)
authorization server (not clear who or what would fulfil this role in your case)
The basic scheme is that the resource owner authenticates using their credentials directly with the authorization server. They are then asked if they want to grant some information (which may just be a persistent identifier, or a description of the information exposed by your api) to some client. When they accept an 'auth code' is sent to the client and they use that (combined with their own credentials) to receive an 'access token'. This access token can then be used to authenticate against the resource server (which can check it's authenticity back against the authorization server).
Normally the way this is used is that the authorization server and the resource server are owned and managed by the same entity (for example google and facebook would fulfil this role) and then clients are independently managed.
The scheme can also be used internally within an organisation without the "explicit grant" which can still at least confirm that a specific end-user is present before releasing any data from an api.

Hiding MySQL Credentials in Application

I need to create an application for a company and they would like to have people login to the application to have different permissions to perform different tasks.
My initial idea was to create a MySQL database, hardcode the credentials into the application and have the application connect to the MySQL database. The MySQL database would then have a table called "users" which would store usernames, passwords and permissions. The application would then query the server and perform the authentication.
The biggest problem with this is having the MySQL credentials hard coded into the application. If the application gets into the wrong hands, they could do lots of damage to the MySQL database if they snoop around to find the credentials and start dropping tables.
So I thought of developing a server that acts as an interface for the MySQL Database. For example, the client application would connect to the Server via TCP, and the server connects to a MySQL database. That way the MySQL credentials are never exposed to end-users. However, this means I have to develop a server application which a) will be harder to maintain and deploy for my customer (as opposed to just setting up a MySQL Server) and b)Has potential to introduce more bugs since I have an additional system I need to make (which relates back to point a for deploying bug fixes, etc)
So I was thinking instead of having a table of users in the database and having the application connect directly to the MySQL server with hardcoded credentials, the end-user would be given actual MySQL user credentials in which they would enter into the application to connect to the MySQL server. This means if someone gets their hands on the application, they can't do any damage to the MySQL database, but there still remains the risk of an end-user giving their credentials to the wrong person.
What are the best ways to have a desktop application connect to a MySQL database? Are there any other solutions other than the 3 I have thought of, or do you have any thoughts on my solutions?
As #Perception noted. Your best bet here is to implement a web service in front of MySQL. You don't want unknown numbers of clients from unknown IP addresses all having access to your database.
It would be really easy to DOS attack you by tying up MySQL connections. Not to mention that you would very severely limit your ability to scale your backend service to meet the demands of an increased client base without having a web service in between.
The web service could also offer you the ability to control user authentication and authorization in any number of ways (user/pass combination, token-based access, OAuth access, etc.).
Where I work there are two practices I have seen:
Each entity (person, thing, or business (depending on level of granularity needed) accessing the database) has their very own credentials. This was used on an MSSQL and on a Rocket Universe database. This is mostly the retail and legacy software.
We host the application ourselves and use a separate authentication system for users. The database credentials are stored on our server where the application is hosted. The client knows nothing of the backing database. These are usually web apps and web services.
Something you could do that we have done is that many of our applications actually talk through a RESTful service that emulates the database in a way. The application itself has no access to the database. I would read the wikipedia article on restful services for more information. Our authentication is done using Nonce encoded HMAC requests where each user is given their very own key tied to their credentials.
Wrapping the database in a web service gives you a few possible advantages:
If you decide to change your database structure while keeping the same information, you might not even need to update the client applications, just the service.
Credentials never leave the server, your credentials remain safe so long as nobody gains access to your server. Security in general is increased.
If you do your service cleverly enough, you could even transfer much of the internal logic that would normally be client side onto the server, making updates and bugfixes virtually seamless to the client.
The disadvantages that I see:
It is one more thing to maintain
Your application is vulnerable to denial of service attacks, but since it is a database that's a possible problem anyway
If the server goes down, all the client applications go down, but again, still a problem anyway.
RESTful architecture: http://en.wikipedia.org/wiki/Representational_state_transfer
HMAC: http://en.wikipedia.org/wiki/Hash-based_message_authentication_code
Our HMAC system works like so:
User logs in using username and password to their local application.
The local application communicates to our authentication service and gets a "Session Key" and shared secret for that username and password.
Using the Session Key (which expires in a short period of time), the application creates an API Key (which lasts a long time) and stores it to the computer. The session key could be used instead of an API Key if the user is required to log in each time. We mainly did it this way for convenience for some programs. If the computer is not secure, the Session Key should be used only and no API key is stored on the local machine. Each time the user logs in, they get a new Session Key.
Each request to the database service is accompanied by a HMAC-signed nonce which the application gets from the authorization service based on the API key. After getting the nonce, the application signs it using the shared secret. These signed requests can only be used once since the web service (which the user could know nothing about) authenticates the request. Once the signed nonce has been authenticated server-side by seeing if hashing the nonce with that particular API/Session Key's shared secret results in the same digest, the nonce is marked expired and the request is granted.
The above is vulnerable to man-in-the-middle attacks if HTTPS is not used, so often people make a message based on the nonce and the URL being requested along with a timestamp and compute the HMAC on that. The server then recreates the message based on the URL, checks to see if the timestamp is within some bounds (+/- 4mins or something), and then authorizes the user based on that information.
To further granulate operations, we also have a role system which checks to see if the user who owns the Session/API Key has been given permission to request the thing that they were requesting. If they have the appropriate role, the request is granted.
Summary: Credentials are done user-by-user, the end user has no knowledge of the database, a web service wraps the database in a RESTful API, and a role based system is used to make permissions granular.
This is just a suggestion and I am not saying this is the best or only way to do this. This just happens to be how we have ended up doing it where I work.
Let's look at two ways of dealing with database:
Client directly connects database, and manipulate database
Server connects to database and provide interface for client to use
Considering your use case:
valid valid serial number or to store/read information about certain user
it can be designed in the following way to provide security. (I'm no expert in this)
Client directly connects database, and manipulate database
You don't have to use your admin to visit database, instead you create a user for client only, and limit user's access privilege to only viewing (certain data). And you can enforce security policy at database by changing privilege for this user.
you can consult MySQL :: MySQL 5.1 Reference Manual :: 6 Security for more info.
6.2 The MySQL Access Privilege System
6.3 MySQL User Account Management
Server connects to database and provide interface for client to use
You can use HTTP and provide interface to client to use. And only the backend connects to the database.
Something like RESTful API, there are many easy to use framework that provides authentication and authorization.
I don't think it's good idea to let client have direct access to database in your case. So if possible, the second option is better.
Also note that password based authentication is not ideal.