signing api calls from frontend to backend - javascript

I am implementing a secure way for the frontend to communicate with the backend using a secret key. The backend is a sensitive service (mobile banking.)
First I was thinking JWT, but the token-based approach has two disadvantages:
a) the front-end has to obtain the token, this means it has to send some auth data to the back-end - and if the front-end can do this, anyone can do this.
b) even if there is some secure way of obtaining the token, anyone can fire up Chrome dev tools and use it while it's not expired.
So the alternative approach is to sign each request from a front-end with a secret key. The key is known to back-end and front-end the front-end is bundled and uglified so as to keep the key secret. We concatenate the request URL and its payload, encrypt them with a secret key and send the resulting hash in a header. The back-end gets the request, does the same encryption and compares the headers; if they are equal - it makes the request.
This leads me to three questions:
Does this really mean that even if the request is sniffed it cannot be reproduced unless the url+payload is the same? Is there something i'm missing?
Is there a JS library implementing this approach? (or maybe something for the backend too - I am using Django)
Is there a better approach?

Bundle as you want, if your security key which authorizes request is inside js i will be able to un-uglify (beautify) and get it. Use SSL to encrypt connection and just use JWT ;)
http://jsbeautifier.org/
You will have to authorize user somehow anyways, so it means sending private data to establish the "session". Let it be username, email, password or some "secret" token.

Related

NodeJS CSRF Protection with Express, GraphQL and CORS enabled

I am creating a web service very much like shopify but using only JS. Nodejs express for an API with GraphQl and Cors enabled. VueJS for frontend. My authentication is running with JWT. But I have things like anonymous checkout so i need a CSRF protection. The thing is my API is not a router. My router is in the frontend and im only getting the data I need via Graphql through Axios calls to the API. I took a look at the csurf module and tried it out but currently the way im getting a CSRF token to the frontend is with a /getCSRFToken endpoint on the API which i've read is not a good practice and the other thing is It's enabled to access to everyone because of the CORS enabled.
This is the main source of information I have: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet
I don't know how to exactly set up the CSRF protection without having am API route for getting the CSRF token and sending it as a cookie through the response and generally make the whole thing secure with the best practices.
I was also thinking about restricting access to the API only for the domains of the shops that are in the system but don't now if that will be any good either.
Any suggestions are welcome
You can generate the cookie client side (using window.crypto), then have the JS read it and send it in a header, the server simply has to verify that they match. But this is vulnerable to the fact the cookie is not HttpOnly (because your JS needs to read it!). For this reason, this method is not best practice, but it is better than nothing.
It also does not prevent users from issuing requests from curl and such once they figure out that they only need to provide a matching cookie and header, but they still cannot issue requests on behalf of other users unless they have the target users authorisation credentials.
There actually isn't anything wrong with having an API route which generates a token per request, although it does result in doubled request density (you need a new token for each request!). The reason for this is that an attacker cannot read the response from an external site (CORS will prevent this). Then you are not vulnerable to any cookie exploit, since you never store a cookie in the first place.
Edit: I see you hint at having CORS * enabled for this endpoint to be public. If your API really is public then you'll have probably better off using OAuth2/JWT authentication instead, this way CSRF becomes irrelevant, since the authentication does not come from cookies.
Trying to keep a value across multiple requests encounters difficulty with history functionality, so it's recommended to either use a token per request or...
You could also store a cookie from the getCsrfToken() request and keep it valid for some time, but make it HttpOnly, since it was issued by the API, the API will be responsible for making sure that it is receiving a valid CSRF token.
The issue with both of the above is that if you want true anonymity then you can't tie these tokens to a particular user, so one user could avoid the CSRF checks on behalf of another by using their own CSRF token!
If you can come up with some way around that whilst maintaining anonymity then the server can check the validity of the tokens that it is receiving, such that one user cannot use their token on behalf of another.
Your last idea (assuming that you want true anonymity) is probably the best. Provided that the user agent is trustworthy, the referer and Origin headers cannot be tampered with, so if you are happy to lock down your API to only the domains which your JS is running on, then doing a referer/Origin check server side will not be easily worked around by an attacker. This isn't best practice, but is practically effective.
Again, curl requests and such can be issued freely, but they can only be issued on behalf of another user if the attacker has the user's authorisation credentials.
The last thing to note is that CSRF is an alternative attack vector to XSS, but if you have XSS vulnerabilities, then CSRF defences usually become obsolete, so make sure that you defend XSS first, before implementing CSRF defence.

RESTful API write security

I've recently started using modern front end technologies like React/Angular and as a result have started using tools like JSON Server to recreate dummy restful db interactions.
My understanding is that most rest api's authenticate via some kind of token and secret that is either passed as part of the url or as a header. This seems fine for retrieving data, but is it not risky exposing these login credentials in a front end language like JS when writing is possible?
My thinking is that all it would take is a simple view source for somebody to steal my token/secret and potentially start populating my db with data.
In the problem that you describe the client (browser) has the login credentials because the server provide them. There is no "exposing" as the credentials are already exposed. Exposing your credentials to every client means that there is no security.
When we talk about security we consider as a client the browser not the real person that operates the browser. As you said, the real person can access all the browser's data.
To secure your API the secret key must be kept secret. This means that each client has a different key and uses it to get their data/services from your RESTfull server.
In a simple senario this key can be used/managed like the session id.
The client should first pass through an authorization process (login maybe) and then a temporary key can be generated for the client's session.
Generally, a key is converted to rights. If every client by default has the key, everyone has the default rights, so you may also remove the key and set the default rights to every request.
A client that you don't want to have full access to your db should have a key that gives him limited access to your db.
On the other hand, if the client provides the key, this is secure. For example a php code on a server that uses the secret key for accessing your API.

POST Call to Authenticate User to Front end Application

I've been tasked with creating an LDAP authentication on a front-end Javascript application.
I am extremely limited on time and have a very small toolset. The toolset is the front-end javascript application and an available C# application which I can make post and get requests to.
I was thinking I could simply make a call such as https://mybackend.com/authenticate
Where I would post a username and password.
And on the backend this would return whether or not the user was valid in the AD. Which I can then use on the front-end to ensure the user has logged in.
Is this approach extremely unsecure or does it have flaws? I'm thinking that if I am posting to the backend above not much will be exposed.
Any tips would be immensely helpful.
Is this approach extremely unsecure or does it have flaws?
This is not insecure, it's the normal way you would do it. One could add more security by adding a CSRF token, which would be validated on the server for any form submit.
And yes, you should send all the data over HTTPS, this will encrypt the payload.
What you are doing is normal for front-end JavaScript framework like Angular. As long as you use Https, you should be ok.
Only issue is how you will handle the subsequence page requests.
There are two ways to handle it –
Easiest way is to use ASP.Net MVC as login page, and use Cookie Owin Middleware. Since same cookie is sent back to server on API calls, you do not need to do any extra works. You can download my sample code at GitHub - OwinAuthenticationService.
Another way is to use Bearer Token in which you will have to send the same token back to server on every page request.
All method are insecure.
Especially without HTTPS.
But you can put the Authentications in the header of message and use a token generated with a key that only server know.

Understanding JWT

I've spent a couple weeks trying to wrap my head around JWT objects. The premise makes sense but where I get confused is the security aspect. If I am a Javascript Client (e.g. Firebase) and want to send a secure request to an api using Open Auth, I would encrypt my message with a key. However, since the client source may be viewed how can I secure my Key so malicious requests don't go through. Am I missing something. Is there a way to secure the key?
Joel, I think you got the directions wrong ;)
One would use JWT within the OAuth protocol to achieve what some people might call "Stateless Authentication", meaning that the auth server would issue a signed token (for e.g. a client application or a user) after successful authentication (of the client or user) without storing info about/ of it, which would be required when using opaque token.
The signed token could be used by your JS client to e.g. call a certain REST-API endpoint (on a so-called resource server) that would verify the signature of the token and authorize your request or not, based on the content (the claims) of the JWT.
Both, your client application as well as the resource server are able to introspect the token and verify its signature because they either have a shared secret with the auth server (who used the secret to sign the token in the first place) or know the public key that corresponds to the private key the auth server used to sign the token (as Florent mentioned in his comment).
JWTs can also be encrypted, which is useful if the resource server or the auth server require sensitive information but don't want to store/ access the data. You would not be able to introspect it as long as you don't have the used encryption secret.
... long story short, the OAuth protocol describes client auth against a resource or an auth server. JWT can be used to transfer auth prove (as a Bearer token within the Authorization header). However, the idea of using JWT in the OAuth flow is not to "send a secure request to an api".
The encryption process is performed using the public key of the recipient.
Your client has no private key to generate and manage.
If you want to receive and decrypt such JWT, then your client has to create a key pair (private and public) for the session only and then exchange the public key with the server.
When building an api server, I prefer the client do the encryption process on their own server, and send the encrypted data after that. Everything is under https.
If the encryption somehow must be done on the web client side, I prefer the key to be very short-lived & time based, and both the api server and client have the agreed special algorithm to generate that key again. Therefore, if the key is hacked somehow, the attacker can not benefit in long term.

How to Encrypt password for REST API authentication

There is a lot resources about how to secure REST API access, but this not what I am looking for. I am going to use provided REST API with Basic Authentication (and this cannot be changed easily :( ).
Obviously I can go with:
var requestOptions = {
hostname: "rest.api.url.com",
path: "/path/",
auth: "username:password"
};
var req = http.request(requestOptions, function (res) {
// some code here
});
Is there a way to not provide password in plain text in the script?
Is there a way to not provide password in plain text in the [JavaScript]?
Client-side JavaScript will always be vulnerable to tampering and modification, including reversing any "encrypted" passwords you store in the client-side script. You can obfuscate your code all you like, but if the password is present in any form in your client script, it is accessible.
I am going to use a provided REST API with Basic Authentication (and this cannot be changed easily
Since you can't change the REST API to use something like tokens or SSL, one solution that comes to mind is to have an intermediary between your server and the REST API which does use SSL. Communicate securely with some server-side script on your server, and have this script proxy the requests and responses from the REST API.
Resources:
How to encrypt data in javascript and decrypt in php?
Secure communication between JavaScript and a Web service in PHP
How to secure the password while it being sent using AJAX?
You can encode it with whatever encryption you like, however your encryption technique will still exist on the client side. The proper thing to do here is to setup a SSL certificate so that your requests become encrypted with the certificate.
Furthermore, to reduce the need to send passwords around you may want to look at using some sort of token based authentication.

Categories

Resources