GOAL : I am creating a mobile app that needs to hit an AWS server and I want to make sure only my app can hit the server.
CONSTRAINTS : I never want the user to have to login to the app. If my research is correct, I believe this eliminates the use of tokens (such as JWT). I think this eliminates the use of tokens because I would have no way of refreshing the token in the user's app.
PROPOSED SOLUTION : Encrypt a key (a string) in the app (let's say the string is "allow") using bcrypt in the mobile app. Use a HTTPS POST request to hit my server with the encrypted key "allow" embedded in the body. In my server logic I would read the contents of the HTTPS POST body, decrypt the string, and allow further logic to be done in the server if the decrypted string = "allow".
QUESTION Does my proposed solution make sense? If not, could I get guidance to what I should do?
I believe this is possible because I read here that the the body of a HTTPS POST is encrypted. Therefore I think placing a bcrypt encrypted key in the body should be an extra layer of security to my server.
Is this for an API? Instead of adding a key value to the POST body, add it to a header value. It will be encrypted over https. If ONLY your mobile app will be using it then you can probably even use the "User-Agent" header.
Whatever header you choose, you would then evaluate it on the server just like you mentioned.
However, do note that someone could figure out how it works. It will only prevent most people from trying to figure it out.
I'm not convinced about the bcrypt key. If you are using https it will be encrypted anyway.
Related
Narrowing down from a broad topic, i have a specific question (maybe a little bit 'tin-foil hat').
This question is regarding the best practices of securing data transmitted in a post request between the client and server. The background is a web app I'm developing to learn more about node and express js.
Although the example i'm using is for login credentials it really could be about any information being transmitted in a post request from a form submit to an express server.
example:
client submits form data through a button click event on the client. I'm using vue for the front end, but this is a generic question. On the client page i'm also using (inside an async function):
const resp = await axios.post("http://someurl.com/login", {client:email, pw:pw});
in chrome developer tools on the network tab i can see the request payload. In the example it looks like:
{client:"some email address", pw:"some password"}
Would it be better to transmit the payload already encrypted / encoded? Then have it decrypted / de-encoded on the server?
For transmitting sensitive information, is it better to use a signed cookie?
The plan, should i ever get through all of this is to use let'sEncrypt for HTTPS.
Is it reasonable to only rely on HTTPS for protecting this type of payload?
For reference, on the express server, password gets hashed and compared with a hashed version from a database. I've read about Helmet, and csurf and intend to use them in the final product as well. There's a lot of great information in this answer. Which is incredibly awesome and talks about the importance of HTTPS over HTTP.
Any additional references / thoughts / practical considerations are appreciated.
Using HTTPS will encrypt your payload between your client and the server.
Any javascript handling on the front end can be circumvented by users with enough knowledge so all frontend is mainly there for is to facilitate a better user experience. Password confirmation checking, correct fields filled out etc.
Your main source of security will be your eventual LetsEncrypt HTTPS certificate and your hashing and salting applied at the server end. As you correctly surmised HTTP send passwords in clear text which is bad. As a warning though even HTTPS can be defeated if somebody wants it bad enough with a number of techniques to high jack Certificate Authorities (I believe Root CAs should be offline anyway) or modify trusted certificates on a users PC.
Although it does depend on the amount of effort required by the hacker vs potential return hence the more you are trying to protect the greater the security required before it becomes not worth the effort for any potential hacker to attempt to circumvent the security of a particular site. (Reputation hacks aside of course)
Hope this helps.
When you use Disqus API on the server side, you have to put 'app_secret' in URLs on every API request. Here is what Disqus doc says:
If you are using the server-side API, you will need to send api_secret with your secret API key value.
(https://disqus.com/api/docs/requests/)
When I call URL like this:
https://disqus.com/api/3.0/threads/list.json?access_token={ACCESS_TOKEN}
I get this error:
{"code":5,"response":"Invalid API key"}
When change URL to this:
https://disqus.com/api/3.0/threads/list.json?access_token={ACCESS_TOKEN}&api_secret={API_SECRET}
It works ok.
I think it is very, very dangerous to use secret key in common GET requests. I don't know any other API that would be required to use secret key in GET requests.
What do you think about it?
It's a server-side request, so from your server to Disqus.com. The client will never see the URL.
As you are using HTTPS, all that is visible in plaintext is that you made a request to a server at a specific IP address. However, an attacker monitoring your DNS requests or using a reverse DNS lookup can easily determine that the IP address belongs to the server at disqus.com.
So in short: It's safe. An attacker can see that you talk to disqus.com, but everything else is encrypted.
Also see this answer and this answer for more.
I’m designing a REST service that needs to be well secured against unauthorized access. I’m thinking about requiring a security digest that’s generated by hashing all request parameters plus a secret key with sha-256 and making the service only available over https. Can anyone tell me if this is sufficient security?
First of all, make sure you are using en HMAC, not a plain SHA-256 to generate the "security digest".
Next, what are you going to put into the input of this digest? You'll want to have at least the method, the URI, the payload, and very possibly most of the headers of the request (there are many headers that affect the meaning of an HTTP request that are important in a REST context). That might be difficult depending on what HTTP client you are using because the client might set or change headers in a way that you do not directly control.
Finally, where are you going to put this digest? A custom header (e.g. X-Request-Authenticator) seems sensible, or maybe a cookie if the client is running in a web browser.
I would recommend using existing tools if you can, instead of creating something yourself. Using SSL already gives you message integrity protection so start with that. Then, if you just need simple access control, HTTP basic auth will work just fine with a REST request. Or you could have the client present a certificate and verify it.
Consider the URL:
https://foo:password#example.com
Does the username/password portion in the above example qualify as a "URL parameter", as defined in this question?
When you put the username and password in front of the host, this data is not sent that way to the server. It is instead transformed to a request header depending on the authentication schema used. Most of the time this is going to be Basic Auth which I describe below. A similar (but significantly less often used) authentication scheme is Digest Auth which nowadays provides comparable security features.
With Basic Auth, the HTTP request from the question will look something like this:
GET / HTTP/1.1
Host: example.com
Authorization: Basic Zm9vOnBhc3N3b3Jk
The hash like string you see there is created by the browser like this: base64_encode(username + ":" + password).
To outsiders of the HTTPS transfer, this information is hidden (as everything else on the HTTP level). You should take care of logging on the client and all intermediate servers though. The username will normally be shown in server logs, but the password won't. This is not guaranteed though. When you call that URL on the client with e.g. curl, the username and password will be clearly visible on the process list and might turn up in the bash history file.
When you send passwords in a GET request as e.g. http://example.com/login.php?username=me&password=secure the username and password will always turn up in server logs of your webserver, application server, caches, ... unless you specifically configure your servers to not log it. This only applies to servers being able to read the unencrypted http data, like your application server or any middleboxes such as loadbalancers, CDNs, proxies, etc. though.
Basic auth is standardized and implemented by browsers by showing this little username/password popup you might have seen already. When you put the username/password into an HTML form sent via GET or POST, you have to implement all the login/logout logic yourself (which might be an advantage and allows you to more control over the login/logout flow for the added "cost" of having to implement this securely again). But you should never transfer usernames and passwords by GET parameters. If you have to, use POST instead. The prevents the logging of this data by default.
When implementing an authentication mechanism with a user/password entry form and a subsequent cookie-based session as it is commonly used today, you have to make sure that the password is either transported with POST requests or one of the standardized authentication schemes above only.
Concluding I could say, that transfering data that way over HTTPS is likely safe, as long as you take care that the password does not turn up in unexpected places. But that advice applies to every transfer of any password in any way.
I'm building a web API very similar to what StackOverflow provide.
However in my case security is importance since data is private.
I must use HTTP.
I can't use SSL.
What solution(s) do you recommend me?
EDIT: authentication != encryption
Nearly every public API works by passing an authentication token for each web request.
This token is usually assigned in one of two ways.
First, some other mechanism (usually logging into a website) will allow the developer to retrieve a permanent token for use in their particular application.
The other way is to provide a temporary token on request. Usually you have a webmethod in which they pass you a username / password and you return a limited use token based on if it is authenticated and authorized to perform any API actions.
After the dev has the token they then pass that as a parameter to every webmethod you expose. Your methods will first validate the token before performing the action.
As a side note the comment you made about "security is important" is obviously not true. If it was then you'd do this over SSL.
I wouldn't even consider this as "minimal" security in any context as it only provides a false belief that you have any sort of security in place. As Piskvor pointed out, anyone with even a modicum of interest could either listen in or break this in some way.
First of all, I suggest you read this excellent article: http://piwik.org/blog/2008/01/how-to-design-an-api-best-practises-concepts-technical-aspects/
The solution is very simple. It is a combination of Flickr like API (token based) and authentication method used by the paiement gateway I use (highly secure), but with a private password/salt instead.
To prevent unauthorized users from using the API without having to send the password in the request (in my case, in clear since there is no SSL), they must add a signature that will consist of a MD5 hashing of a concatenation of both private and public values:
Well know values, such as username or even API route
A user pass phrase
A unique code generated by the user (can be used only once)
If we request /api/route/ and the pass phrase is kdf8*s#, the signature be the following:
string uniqueCode = Guid.NewGuid().ToString();
string signature = MD5.Compute("/api/route/kdf8*s#" + ticks);
The URL of the HTTP request will then be:
string requestUrl =
string.Format("http://example.org/api/route/?code={0}&sign={1}", uniqueCode, signature);
Server side, you will have to prevent any new requests with the same unique code. Preventing any attacker to simply reuse the same URL to his advantage. Which was the situation I wanted to avoid.
Since I didn't want to store code that were used by API consumer, I decided to replace it by a ticks. Ticks represents the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001.
On server side, I only accept ticks (timestamp) with a tolerance of +-3 minutes (in case client & server are not time synchronized). Meaning that potential attacker will be able to use that window to reuse the URL but not permanently. Security is reduced a little, but still good enough for my case.
Short answer: if it's supposed to be usable through usual clients (browser requests/AJAX), you're screwed.
As long as you are using an unencrypted transport, an attacker could just remove any sort of in-page encryption code through a MITM attack. Even SSL doesn't provide perfect security - but plain HTTP would require some out-of-page specific extensions.
HTTP provides only transport - no secure identification, no secure authentication, and no secure authorization.
Example security hole - a simple HTTP page:
<script src="http://example.com/js/superstrongencryption.js"></script>
<script>
encryptEverything();
</script>
This may look secure, but it has a major flaw: you don't have any guarantee, at all, that you're actually loading the file superstrongencryption.js you're requesting. With plain HTTP, you'll send a request somewhere, and something comes back. There is no way to verify that it actually came from example.com, nor you have any way to verify that it is actually the right file (and not just function encryptEverything(){return true}).
That said, you could theoretically build something very much like SSL into your HTTP requests and responses: cryptographically encrypt and sign every request, same with every response. You'll need to write a special client (plus server-side code of course) for this though - it won't work with standard browsers.
HTTP digest authentication provides very good authentication. All the HTTP client libraries i've used support it. It doesn't provide any encryption at all.