I have an API App ID I want to hide, but I have to use it in the client to make a call to a 3rd party library.
So I encrypted the App ID on the server, and when the iOS Client app launches, it sends a GET request to the server requesting the encrypted App ID, and the AES key to decrypt it.
The response looks like that:
key: "aes key needed to decrypt app_id"
app_id: "encrypted app_id"
The issue I have is:
Let's say someone makes an external call using Postman, cURL etc. to the same endpoint as the iOS Client makes to get the keys and he gets the data himself (as the response is just plain text).
What stops an attacker from taking the AES key and the app_id and just trying to decrypt it with different methods (AES128, AES256, and so on...)?
So what I'm basically looking for is a way to prevent attackers from exploiting my 'GET /keys' endpoint, so as to make it hard for them to actually retrieve the real value of the app_id, while at the same time the iOS Client should know how to retrieve the real value of the app_id from that endpoint.
Related
I'm wanting to receive a POST request sent from a backend java application that sends user account information (e.g. username, email, etc.) and will create an account with the given information. What method can I go about where the api I have can only be used from my java backend (so people can't just start creating accounts themselves)? I assume a method would be using an api key but I have had trouble finding resources on how to implement that. Could someone help me and steer me in the right direction?
The most common method is by the use of API Keys.
You would have a list of valid clientsIds for your NodeJS Server (Note that the JAVA backend server would act as a client for your Node JS server when creating users).
Along with the list of valid clients, you would also need to store a valid API Key for each client.
The Java Backend would send you its clientId and the API Key in the POST request. You would need to validate the client id and the API Key for that client.
Once both are validated, you can assume the request to be from your Java backend.
Both the list of valid clientIds and the associated API Keys should be stored in environment variables. The API Keys should be different for the same client in different environments.
Another way I have implemented this in the past, and I consider to be more secure, is by use of RS256 Algo JWT Tokens with the use of Public and Private keys.
Your Java backend should generate a Public/Private key pair and provide the Node backend the public key.
Along with the POST Request, the Java Backend will generate and sign JWT token using the Private Key and send it to your NodeJS Backend.
Your NodeJS backend should verify the token using the public key.
The JWT Token generated by the Java backend should be short lived.
Every time the Java Backend has to send a POST request, it should generate a new JWT token.
The use of JWTs are more secure as they can be short lived and you dont have to worry about a token being leaked. If the API Key gets leaked, you will have to co-ordinate between the two backends to start using a new API Key. However, if a JWT token gets leaked, the same token cannot be used once it expires. It would be safe to have the JWT token short-lived, may be 1-2 minutes. Since the Private and Public keys are not being sent along with each request, there is a lesser chance of it being leaked.
This may seem like a pretty noobish question, but I just recently got into Node.js and am needed to make sure that the same kind of Authentication that occurs in my Laravel App happens in Node.js.
Clearly, I need to use an API, but I am confused about how to do it in a manner that is secure. I have looked into this article:
https://www.ida.liu.se/~TDP024/labs/hmacarticle.pdf
And have looked through their algorithm into building an API. But I do not understand how it would be secure.
According to the post, you store a public and private key in a Database. The public key can be seen by everyone but the private key is, well, private. However, when sending it to the server, you send a hashed version along with other data, of the private to the server.
This sounds all well and fine. However, does that not mean that the public key and the hash is public, thus the private key is exposed as well?
For example lets say I try to establish the following connection
ws://example.com/pull?public=A89-3NJ2-KAN-NKSN1&hash=QmFzZTY0IHRoZSBoZWxsIG91dCBvZiBtZSBiYWJ5Li4uLi4u
What stops another user from just sharing this link giving an unrelated user access to it?
The article you linked to describes how to authenticate one single request, not an entire session. That is, the user sends the public api_key along with some request data that describes the specific request for the API (like, { "action":"latest_price", "symbol":"GOOG"} for a stock market API).
To authenticate, the user also uses a shared API-access secret key as an HMAC key to compute HMAC(secret, api_key+request). No one else can compute this if they don't know the secret. Only the user and the server should know secret, because it's basically the user's password to use the API.
The situation you describe is very different: you're using a WebSocket, so I assume you'll be sending requests interactively. If you want to authenticate the entire socket session, this approach doesn't make sense, since it's designed to authenticate a single request. You can apply this approach to individual requests inside the WebSocket connection.
For authenticating a new connection (i.e., "what logged-in user is opening this connection?") using auth cookies is appropriate, just as you would for a traditional HTTP connection.
Below, I'll assume that the purpose of the Web Socket is to send only one request (which really makes me wonder why it's a WebSocket), so that the request-level authentication makes sense.
What stops another user from just sharing this link giving an unrelated user access to it?
Nothing. Do you want someone else to submit a specifc request, while impersonating you? Then by all means, give them that link and tell them to use it.
The credentials in the link include an HMAC of the API request (plus your identity) that only you can generate, as the sole owner on your API secret key. If you give that HMAC to someone else, they can submit it and impersonate you for that specific request. However, they cannot create more requests, because they don't have your API secret to make more HMAC values for different requests.
In fact, if you didn't want that request to be submitted, you should not have used your secret to create the authenticating HMAC in the first place! Why did your authenticate a request that you didn't intend to be submitted?
Have a look at this
Essentially
make a "websocket preauth" request to the backend from the browser using the site's normal auth
backend returns a CSRF token in the response body and sets a "websocket auth" cookie with SameSite=Strict in the response headers
attempt to establish a websocket connection with the backend, with the addition of the CSRF token in a query parameter
the backend checks
that the websocket auth cookie and CSRF token are valid
that the value of the Origin header matches an approved domain
the backend sends a response and upgrades the connection to use websockets
I try to create a Web application with JWT:
If a user send a request the server, I can run the process on the server and send the data back to the browser in a web token, that brings me to the question:
How can I verify this server response in the browser and send a new request to the server by using JWT with a secrete that can be accept from the server?
On the server the JWT from the browser request should be verify.
My consideration is to create a JWT on the client with the same "secret" but this is readable for attackers, because it is possible to read the source code (developer console).
Does there exist an way?
//Create request JWT
Request 1 --> {head: ...; data:..., secrete: secret}
//Request should be checkted on the server (secrete)
// create a Resonse JWT and send back to the Client
Resonse 1 --> {head: ...; data:..., secrete: secret}
//Client verify the Respons JWT by the secrete
Keep secret the private keys. Sending them along the net is a dangerous solution because if they are stolen break the full system. You can use an assymetric RSA key pair instead of a symmetric. The JWT is signed with the private key and verified with the public
In the usual scenario, when user is not identified, the server requires credentials to user in the browser, and issues a new JWT token. The client application in the browser include the JWT token in subsequent requests to authenticate. The server verifies token signature.
You propose that the browser also issue JWt tokens as a form of authentication. Consider the following:
you will need an assymetric key pair
generate the keys in the browser, do not send the private key by network
keep the key safe: I suggest using the native webcryptography api, because unlike any other cryptographic library, allows to generate and use keys without exposing the content, ie can not be stolen
send the public key to server and associate it with the user's account
I'm new to cryptography and I'm trying to prevent against man-in-the-middle-attack in a web service I'm developing. The way the web service work is that a user registers on the service using his email address and password and creates an application. Each application is given an application id and an application key. The application id is public (that's how the public communicates with that application) but the application key is private. The user credits his application by loading a pin (a 16 digit numeric string). Loading the pin is done via a HTTP Get request.
Now here is my question: how can the user do a HTTP GET request with his application id (the way the server identifies the application) and his application key (the way the server authenticates him) without compromising his application key?
Because our server has SSL (and I read that SSL protects against man-in-the-middle-attack), I was thinking about simply having users submit their application id and application key as parameters in the GET request, but after reading around, I decided this may not be secure. This is also because after doing the HTTP GET request to load the pin, the user may configure his account that we submit the server response via another HTTP GET request to a URL of his choice. And since we want to do an echo back of his application id and application key so he can authenticate that the request was really from us, I was worried his key might be compromised.
So I decided we should have the user do a md5 hash of his app id and app key to provide a hashed parameter and submit that instead of his app key in the GET request. Then on our server, since we already know the user's app id and app key, we can simply do an md5 hash of both and compare it with the hash parameter the user submitted. But then I also thought that may be insecure because if someone intercepts the hash parameter, the attacker can use that same hash parameter to submit several requests since the app id and app key is static. So in the long run, the hash parameter is no different from the app key.
Now I'm thinking, we should have the user do a md5 hash of his app id, his app key and the pin he wants to load to get the hash parameter. This way, since the pin is always different each time, even if an attacker intercepts a request, the authentication process would not be compromised for other requests because the attacker would not be able to reuse that hash with other requests.
For example, if a user has the following credentials:
1. app_id: 1234
2. app_key: bghuTHY678KIjs78
And a user wants to load the pin: 1234567890123456
He generates the hash by doing an md5 hash of "1234:bghuTHY678KIjs78:1234567890123456". That gives him 210a4c92d85473af9d5f48b4ee182ddd. Then he does a HTTP Get request to the address below:
https://example.com/process?app_id=1234&pin=123456789012&hash=210a4c92d85473af9d5f48b4ee182ddd
Is this method secure? Or should I simply just have the users submit their app id and app key in the HTTP GET request since we have SSL?
The user secret should never be sent over the network. Instead, ask the user to sign his requests using his secret. HMAC is the relevant algorithm.
By the way, MD5 is obsolete and insecure for all crypto needs.
Use Secure Remote Password (SRP6a) and register a password verifier and salt for the 16 digit pin. The pin you never send to the server (you can store it in browser local storage for convenience of the user). Then authenticate the client using SRP6a which results in a strong shared secret session key for each successful authentication. Then use HMAC SHA256 to sign API calls using the session key. See the thinbus-srp JavaScript library and its demos of using SRP6a to authenticate resulting in a session key. See the JWS "HS256" (HMAC with SHA-256, 256+ bit secret) algorithm and any library implementing that as an example of signing a web API with a shared secure key.
The SRP6a authentication protocol is a secure zero-knowledge password-proof where the server does not know the password. The server issues a random challenge to the client which generates a password-proof based on the challenge. The server uses the verifier the client provided for their password to check the password-proof. If the 16 digit pin uses uppercase letters like a standard software license key it is infeasible to run a dictionary attack on the verifier. Use the modern browser webcrypto secure random number generator to generate the pin at the browser. Even you won't be able to obtain the password.
The overhead of using SRP6a to authenticate is that you need the client to first fetch the server challenge. The benefit for your use case is that if the client provides a good password-proof based on the challenge the both the client and server share a secure session key. No-one intercepting the traffic can know the session key. With that shared secret you can sign and verify every API call and verify the signature at the server. No-one intercepting any part of any exchange between you and the client end-to-end from registration through to usage can gain any advantage.
I'm creating an app for Windows Phone and Android. So right now Im building a webapi they both can use, but I want to secure it som non other then my applications can use it. How do I go about it? No one else then my apps is going to access these APIs.
I don't want to implement OAuth.
I've got two scenarios that I'm thinking of:
First (I store username and hashed password on the client):
basic-auth over https/ssl, thats it.
Second (I store accesstoken on the client):
basic-auth over https/ssl to receive a access token.
to get access token, user sends a request for requestoken a token that verifies that both the client and server knows the clientsecret.
for each call to the API the accesstoken has to be sent with to check access
The problem as I see the second approach is that the server sends accesstoken to the client, if anyone where to get this they would have the access of the user.
How is it done in the real world?
You could use a slight modification of First:
store username and password on client
basic-auth over https
Storing a password hash on the client, then sending the hash and comparing it with the hash in the database is equivalent to storing a plain text password in the database because the hash becomes the password. So, your apps should authenticate with a username and password like any human user would do.
But your concerns for the second approach apply too. If somebody intercepts the message, he has your credentials.
A more secure solution is HMAC authentication (now we're talking "real world").
a user has a secret key that is stored on server and client
each request gets canonicalized (transformed into a distinct string, which contains the request method, URI, parameters and timestamp)
the canonicalized request gets hashed with HMAC using the secret key, hash and user id are passed in the HTTP Authorization header
on the server, a hash is generated using the same algorithm (with timestamp from the HTTP Date header) and compared with the sent hash.
if the results are equal, the request is authenticated
An example is the Amazon S3 REST API - the linked documentation is also a good example how to implement it for your own API.