When chunking client code with webpack, i.e. using React lazy loading, is there any way to restrict access to a particular chunk by gating it behind some sort of authorization credentials?
All approaches I've seen so far have involved client-side code that only renders a given component when certain conditions are met on the client side (e.g. something along the lines of this as a simple example). This does not strike me as particularly secure, more "security by obscurity" than anything: a motivated attacker could modify either the client code they do have, or perhaps their own memory, to force the browser to request the additional chunks - or just send requests to the server using some other agent.
Is there any way to enforce this on the server side, in the CDN that serves the client code? Perhaps some way to attach credentials to the requests to obtain additional chunks such that the CDN could verify that the client is indeed authorized to be sent the code? (The server side authorization would be trivial enough to implement myself, but I don't know of a way to have the requests actually attach the credentials - that whole mechanism is opaque and I can't find any documentation.)
Alternatively, is there some justification for the client-side-only approach actually being secure?
Related
I am building a frontend application using react and I am wondering whether it is risky to expose API endpoint URLs (ex: https://myapi.com/v1/getitems) on GitHub, assuming that the endpoint has several security measures that are not exposed such as CORS and JWT Token Bearer Authentication. I would assume not, since, if someone were to take the endpoint and send requests, they would need a token and be allowed to do so by CORS.
Is there any security risk in doing so?
Yes. Don't add the base url of your api on github in plain view. Even though you might have CORS and Authorization, that doesn't stop a malicious actor to keep spamming your back-end.
What you do is create a .env file in your root folder. You can use a library like #beam-australia/react-env and there are others as well.
You add in the .env file the values that are important for your environment and that are usually secrets, and you want them to not be visible in your code. You do it like so:
API_URL="https://myapi.com/v1"
And then you access this variable in your code with env("API-URL") ( in the #beam-australia/react-env case, but others libraries work the same). Keep in mind that you need to add .env in .gitignore so that the .env file is not pushed to github.
Regarding requests, you can make one like so:
fetch(`${env("API_URL}/getitems`)
This way your code will be stripped of the API's base url and if someone sees your code it will see only the endpoint, not the full url.
Publishing the code of the API is risky on its own. Somebody can find a vulnerability in it and instantly hack it. If you add the address of the API to the code you help this kind of attacks. They can get the address with some investigation; OSINT and social engineering too, but better to reduce the attack surface.
As of the secrets, they must never be near to the code, because you or another developer can accidentally publish it. It happened too many times with many developers, so better to take this seriously. If you want to keep the address in secret, then you must extract it from the code and put it in the configuration of the production environment which is imported from a totally different location than your code. Using environment variables like Alex suggested is a good idea for this. Nowadays it is common to use docker, which has a way to manage secrets, so you don't need to reinvent the wheel: https://docs.docker.com/engine/swarm/secrets/ Another aspect that the configuration belongs to the actual instance. In OOP terms you want to describe the injected properties of an object in its class or in a global variable, which is an antipattern.
As of client side REST clients like javascript applications running in the browser or Android/iOS apps, you must not publish your secrets along with the REST client, otherwise it is not a secret anymore. In that case you need a server side part for the REST client and for example sign and encrypt JWT there with a secret key. It is your decision whether this server side part of the REST client sends the HTTP request to the REST API and in that case you can hide the URI of the REST API or it just manages the JWT and the client side part of the REST client sends it. If the server side part of the REST client sends the HTTP request to the REST API, then you can even use traditional sessions with session cookies between the client side and the server side parts of the REST client, but you cannot use them between the server side part of the REST client and the REST API where the communication must be stateless. Though it does not make much sense to have a separate REST API if you don't have multiple different REST clients in this scenario e.g. browser clients for JS and JSless browsers, Android and iOS clients, fully automated clients running on servers, etc. So don't confuse the REST client - REST API relationship with the browser - HTTP server relationship, because they are not necessarily the same. Most of the REST clients run on servers, not in the browser.
I make a web service and I'm going to use a React. A data for the service will be fetch from my API.
But there is a simple way to find out which endpoints I'm using, and what data I'm sending. This knowledge gives a lot options to make bots for my service.
Is there any option to prevent this?
I know, I can require a signing all requests, but it's also easy to get to know.
This cannot be done. Whatever is done in client-side JavaScript, can be reverse-engineered and simulated.
Efforts should be focused on preventing API from being abused, i.e. throttling or blacklisting clients based on their activity or available information (user agent, suspicious request, generated traffic). If the use of API allows captcha, suspicious clients can be asked for proving their humaneness.
There are half-measures that can be applied to client side application and make it less advantageous for abuse (and also for development).
Prevent unauthorized access to unminified/unobfuscated JS AND source maps. There may be a need to authorize them on per user basis. This will make debugging and bug reporting more difficult
Hard-code parts that are involved in request signing to browser APIs, e.g.:
apiKey = hash(NOT_SO_SECRET_KEY + document.querySelector('.varyingBlock').innerHTML)
This requires bots to emulate browser environment and makes their work much less efficient. This also affects the design of the application in negative way. Obviously, there will be additional difficulties with SSR and it won't translate to native platforms easily.
here two basic preventive measures that you can use.
Captcha
Use a captcha service like recaptcha. so that user can use your website only after passing the captcha test. Its highly difficult for bots to pass the captchas.
Rate Limit Api usage.
Add rate limiting to your api. so that a logged in user can only make 100 requests in 10 minutes, the numbers will depend on you use case
Contemplating building an Angular 2 front-end to my website. My question is not necessarily related to Angular but I want to provide full context.
Application logic that displays content to user would shift to the client. So on the server side, I would need to expose data via a RESTful JSON feed. What worries me, is that someone can completely bypass my front-end and execute requests to the service with various parameters, effectively scraping my database. I realize some of this is possible by scraping HTML but exposing a service with nicely formatted data is just a no-brainer.
Is there a way to protect the RESTful service from this? In other words, is there a way to ensure such service would only respond to my Angular 2 application call? Authentication certainly isn't a solution here - I don't want to force visitors to authenticate and the scraper could very well authenticate and get access, anyway.
I would recommend JWT Authorization. One such implementation is OAuth. Basically you get a json web token ( JWT ) that has been signed by an authority you trust that tells about the user and what resources they can access on your api.
If the request doesn't include an Authorization token - your API rejects it.
If the token has been tampered with by someone trying to grant themselves privledges after the token is signed by the authorization authority - your API rejects it.
It is a pretty cool piece of kit.
This site has information about OAuth implementations in different languages, hopefully your favorite is listed.
Some light bed time reading.
There is no obvious way to do it that I know of, but a lot of people seem to be looking at Amazon S3 as a model. If you put credentials in your client code, then anyone getting the client code can see them. I might suggest that you could write the server to pass a time limited token back to the browser with the client code. The client code would be required to pass it back to the server for access. This would prevent anyone from writing their own client code, as only client code sent by the server would work, though only for some period of time. The user might occasionally get timeouts, but that depends on how strict you want to make the token timeouts. Of course, even this kind of thing could be hacked by someone making a client request to get a copy of the token to use with their own client API, but at that point you should be proud that someone is trying so hard to use your API! I have not tried to write such a thing, so I don't have any practical experience with the issue. I myself have wondered about it, but also don't have enough experience with this architecture to see what, if anything, others have been doing. What do angularJS forums suggest?
Additional References: Best Practices for securing a REST API / web service
I believe the answer is "No".
You could do some security by obscurity type stuff. Your rest API could expose garbled data and you could have some function that was "hidden" in your code un-garble it. Though obviously this isn't fool proof, but if you expose data on a public site it's out there regardless of server or client rendering.
I've been putting together a single-page application using React and React-Router and I can't seem to understand how these applications can be secured.
I found a nice clear blog post which shows one approach, but it doesn't look very secure to me. Basically, the approach presented in that post is to restrict rendering of components which the user is not authorized to access. The author wrote a couple more posts which are variations on the idea, extending it to React-Router routes and other components, but at their hearts all these approaches seem to rely on the same flawed idea: the client-side code decides what to do based on data in the store at the time the components are composed. And that seems like a problem to me - what's to stop an enterprising hacker from messing around with the code to get access to stuff?
I've thought of three different approaches, none of which I'm very happy with:
I could certainly write my authorization code in such a way that the client-side code is constantly checking with the server for authorization, but that seems wasteful.
I could set the application up so that modules are pushed to the client from the server only after the server has verified that the client has authority to access that code. But that seems to involve breaking my code up into a million little modules instead of a nice, monolithic bundle (I'm using browserify).
Some system of server-side rendering might work, which would ensure that the user could only see pages for which the server has decided they have authority to see. But that seems complicated and also seems like a step backward (I could just write a traditional web app if I wanted the server to do everything).
So, what is the best approach? How have other people solved this problem?
If you’re trying to protect the code itself, it seems that any approach that either sends that code to the client, or sends the code able to load that code, would be a problem. Therefore even traditional simple approaches with code splitting might be problematic here, as they reveal the filename for the bundle. You could protect it by requiring a cookie on the server, but this seems like a lot of fuss.
If hiding the internal code from unauthorized users is a requirement for your application, I would recommend splitting it into two separate apps with separate bundles. Going from one to another would require a separate request but this seems to be consistent with what you want to accomplish.
Great question. I'm not aware of any absolute best practices floating around out there that seem to outstrip others, so I'll just provide a few tips/thoughts here:
a remote API should handle the actual auth, of course.
sessions need to be shared, so a store like redis is usually a good idea, esp. for fast reads.
if you're doing server-side rendering that involves hydration, you'll need a way to share the session state between server and client. See the link below for one way to do universal react
on the client, you could send down a session cookie or JWT token, read it into memory (maybe using redux and keep it in your state tree?) and maybe use middleware (a la redux?) to set it as a header on requests.
on the client, you could also rely on localStorage to save the cookie/JWT
maybe split the code into two bundles, one for auth, one for the actual app logic?
See also:
https://github.com/erikras/react-redux-universal-hot-example for hydration example
https://github.com/erikras/react-redux-universal-hot-example/issues/608
As long as the store does not contain data that the user is not authorized to have, there shouldn't be too much of a problem even if a hacker checks the source and sees modules/links that he shouldn't have access to.
The state inside the store as well as critical logic would come from services and those need to be secured, whether it's an SPA or not; but especially on an SPA.
Also: server-side rendering with Redux isn't too complex. You can read about it here:
http://redux.js.org/docs/recipes/ServerRendering.html
It's basically only used to serve a root html with a predefined state. This further increases security and loading speeds but does not defy the idea behind SPAs.
I've read quite a few SO threads about authentication and authorization with REST and Angular, but I'm still not feeling like I have a great solution for what I'm hoping to do. For some background, I'm planning to building an app in AngularJS where I want to support:
Limited guest access
Role-based access to the application once authenticated
Authentication via APIs
All of the calls to the REST API will be required to occur over SSL. I'd like to do build the app without breaking RESTful principles, namely not keeping session state stored on the server. Of course, whatever is done vis-a-vis authorization on the client-side has to be reinforced on the server side. Since we need to pass the entire state with each request, I know I need to pass some sort of token so that the backend server receiving the REST request can both authenticate and authorize the call.
With that said, my main question is around authentication - what are the best practices here? It seems there are lots of different approaches discussed, here's just a few that I've found:
http://broadcast.oreilly.com/2009/12/principles-for-standardized-rest-authentication.html
http://frederiknakstad.com/2013/01/21/authentication-in-single-page-applications-with-angular-js/
http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html
There was a similar question asked (AngularJS best practice application authentication), but unless I'm misunderstanding the answer, it seems to imply that a server session should be used, which is breaking RESTful principles.
My main concern with the Amazon AWS and the George Reese article is it seems to assume that the consumer is a program, rather than an end user. A shared secret can be issued to a programmer in advance, who can then use it to encode calls here. This isn't the case here - I need to call the REST API from the app on behalf of the user.
Would this approach be enough? Let's say I have a session resource:
POST /api/session
Create a new session for a user
To create a session, you need to POST a JSON object containing the "username" and "password".
{
"email" : "austen#example.com",
"password" : "password"
}
Curl Example
curl -v -X POST --data '{"username":"austen#example.com","password":"password"}' "https://app.example.com/api/session" --header "Content-Type:application/json"
Response
HTTP/1.1 201 Created {
"session": {
"id":"520138ccfa4634be08000000",
"expires":"2014-03-20T17:56:28+0000"
}
}
Status Codes
201 - Created, new session established
400 - Bad Request, the JSON object is not valid or required information is missing
401 - Unauthorized, Check email/password combo
403 - Access Denied, disabled account or license invalid
I'm leaving out the HATEOAS details for clarity. On the backend, there would be a new, limited duration session key created and associated with the user. On subsequent requests, I could pass this as part of the HTTP headers:
Authorization: MyScheme 520138ccfa4634be08000000
Then the backend servers would be responsible for digesting this out of the request, finding the associated user and enforcing authorization rules for the request. It should probably update the expiration for the session as well.
If all this is happening over SSL, am I leaving the door open to any kind of attacks that I should be protecting against? You could try to guess session keys and place them in the header, so I suppose I could additionally append a user GUID to the session key to further prevent brute force attacks.
It's been a few years since I've actively programmed and I'm just getting back into the swing here. Apologies if I'm being obtuse or unnecessarily reinventing the wheel, just hoping to run my ideas by the community here based on my reading thus far and see if they pass the litmus test.
When someone asks about REST authentication, I defer to the Amazon Web Services and basically suggest "do that". Why? Because, from a "wisdom of the crowds" point of view, AWS solves the problem, is heavily used, heavily analyzed, and vetted by people that know and care far more than most about what makes a secure request than most. And security is a good place to "not reinvent the wheel". In terms of "shoulders to stand on", you can do worse than AWS.
Now, AWS does not use a token technique, rather it uses a secure hash based on shared secrets and the payload. It is arguably a more complicated implementation (with all of its normalization processes, etc.).
But it works.
The downside is that it requires your application to retain the persons shared secret (i.e. the password), and it also requires the server to have access to that a plain text version of the password. That typically means that the password is stored encrypted, and it then decrypted as appropriate. And that invite yet more complexity of key management and other things on the server side vs secure hashing technique.
The biggest issue, of course, with any token passing technique is Man in the Middle attacks, and replay attacks. SSL mitigates these mostly, naturally.
Of course, you should also consider the OAuth family, which have their own issues, notably with interoperability, but if that's not a primary goal, then the techniques are certainly valid.
For you application, the token lease is not a big deal. Your application will still need to operate within the time frame of the lease, or be able to renew it. In order to do that it will need to either retain the user credential or re-prompt them for it. Just treat the token as a first class resource, like anything else. If practical, try and associate some other information with the request and bundle it in to the token (browser signature, IP address), just to enforce some locality.
You are still open to (potential) replay problems, where the same request can be sent twice. With a typical hash implementation, a timestamp is part of the signature which can bracket the life span of the request. That's solved differently in this case. For example, each request can be sent with a serial ID or a GUID and you can record that the request has already been played to prevent it from happening again. Different techniques for that.
Here is an incredible article about authentication and login services built with angular.
https://medium.com/opinionated-angularjs/7bbf0346acec
This SO question do a good job of summing up my understanding of REST
Do sessions really violate RESTfulness?
If you store a token in a session you are still creating state on the server side (this is an issue since that session is typically only stored on the one server, this can be mitigated with sticky sessions or other solutions).
I'd like to know what your reasoning is for creating a RESTful service though because perhaps this isn't really a large concern.
If you send a token in the body along with every request (since everything is encrypted with SSL this is okay) then you can have any number of servers (load balanced) servicing the request without any previously knowledge of state.
Long story short I think aiming for RESTful implementations is a good goal but being purely stateless certainly creates an extra layer of complexity when it comes to authentication and verifying authorization.
Thus far I've started building my back-ends with REST in mind, making URIs that make sense and using the correct HTTP verbs, but still use a token in a session for the simplicity of authentication (when not using multiple servers).
I read through the links you posted, the AngularJS one seems to focus just on the client and doesn't seem to explicitly address the server in that article, he does link to another one (I'm not a Node user so forgive me if my interpretation is wrong here) but it appears the server is relying on the client to tell it what level of authorization it has which is clearly not a good idea.