I have looked through quite a few tutorials (e.g. this, this, and this) on user authentication in a full-stack Django + React web app. All of them simply send username and password received from the user to the backend using a POST request. It seems to me that, if the user leaves the computer unattended for a minute, anyone can grab his password from the request headers in network tools in the browser. Is this a valid concern that must be taken care of? If so, how should these examples be modified? A tutorial / example of the correct approach would be appreciated.
It seems to me that, if the user leaves the computer unattended for a minute, anyone can grab his password from the request headers in network tools in the browser
If the user leaves the computer unattended then what you are describing will probably be the least of his/her worries.
Authentication is a complex topic, if you really do not want to use existing libraries that handle this for you then you will need to spend quite some time to get things right (knowing that even then, risk 0 does not exist), the most basic thing being to never store plain text credentials on your DB and using https to transmit them over an encrypted connection. You can then start thinking about JWTs, avoiding local storage, CSRF and securing cookies, refresh tokens, etc.
You cannot do much however about cases like the one you describe of people giving away access to their computers or sharing their passwords with others except reminding them they should never do such a thing.
On a side note, if the user didn't have the network monitoring tool open when making the request to your website, opening it afterwards will not show the previously submitted plain text credentials (there are workarounds to this however)
Related
I'm looking for some information about a problem that I never thought about, and that I can't find much on the internet (or I'm looking wrong).
Here it is, for a dashboard project in my company, I need to be able to set up a system to store one account per client, or I just have to click on the account in question to connect, like twitter, google or instagram for example.
After the person has added his account, it appears in a list that can switch whenever he wants. Only I don't really see how to set this up, storing the login information in the localStorage? or the jwt token? I confess that I can't find a correct and secure solution as it should be, that's why I'd like to know if some people would have already done that, or if I can be oriented on an interesting solution?
Thanks a lot!
(Sorry for my english, i'm french and it's not perfect ^^)
Do not use localStorage. LocalStorage is not secure at all and can easily be hijacked through any js code running. If you need to store sensitive information, you should always use a server side session.
When a user logs into your website, create a session identifier for them and store it in a cryptographically signed cookie. If you're using a web framework, look up “how to create a user session using cookies” and follow that guide.
Make sure that whatever cookie library your web framework uses is setting the httpOnly cookie flag. This flag makes it impossible for a browser to read any cookies, which is required in order to safely use server-side sessions with cookies. Read Jeff Atwood's article for more information. He's the man.
Make sure that your cookie library also sets the SameSite=strict cookie flag (to prevent CSRF attacks), as well as the secure=true flag (to ensure cookies can only be set over an encrypted connection).
Each time a user makes a request to your site, use their session ID (extracted from the cookie they send to you) to retrieve their account details from either a database or a cache (depending on how large your website is)
Once you have the user's account info pulled up and verified, feel free to pull any associated sensitive data along with it
Background
I am looking at the OAuth 2.0 Implicit Grant flow where a user is redirected to an authentication service and a JWT token is sent back a Single Page Application(SPA). The token is stored in a cookie or in local storage and, in the examples i have seen, the application will hide/show certain pages based on whether it can find the token in storage.
Issue
The problem is that in all the examples (official from service providers), i was able to manually add any random but properly formed token to the browser's local storage and got access to the 'secured' pages.
It was explained to me that you cannot validate the token in the SPA because that would require exposing the client secret and that you should validate the token on the API server. This means that you can 'hide' the pages but it is really easy to see them if someone wants to. Having said that you are unlikely to cause any real damage because any data retrieval or actions would need to go through the API server and the token should be validated there.
This is not really a vulnerability but the documentation and examples I have seen do not explicitly cover this nuance and i think that it could lead naive programmers (like myself) to think that some pages are completely secure when it is not strictly the case.
Question
It would be really appreciated if, someone who is better informed than i am, confirm that this is indeed how SPA authentication supposed to work?
I am far from an expert, but I have played a bit in this space. My impression is that you are correct, any showing/hiding of functionality based solely on the presence of a token is easily spoofed. Your SPA could, of course, get into verifying an access token.
But that may just make it a little more challenging to spoof. If someone wants to fake the client into thinking it has a valid token, they can likely manipulate the client-side JS to do that. Unfortunately that's the nature of client-side JS. Much of the code can be manipulated in the browser.
Thus far this is speaking to protecting the user from seeing a UI/UX. Most applications are only beneficial when they have data to populate their UI. That's where the API access token strategy is still sound. The server will verify the token and not give the client any data without it.
So while it's unfortunate that JS can be easily spoofed and manipulated to show things the developer would rather not make visible, this isn't typically a deal-breaker. If you have some awesome UI feature that doesn't need data, and you need to secure access to that UI itself, this model may not be the greatest.
I'm building an admin page for an application and have a state value 'authenticated' that flips from 'false' to 'true' after a successful login (which is authenticated on the server) which then shows the actual admin panel.
Are component state values safe from tampering by the client? Basically, if the client can modify my 'authenticated' state value to 'true', they can skip the login and go straight to the admin panel (which I obviously don't want).
I read that React Dev Tools allows the client to modify values yet everyone says "validate on the server" but I am validating on the server and updating my state accordingly, if the user is approved. If it is not wise to have a state value manage this, what is the right way to conditionally show the admin page after a successful, server-side authenticated login?
I think this is an important question since tampering with state values in a React app can have huge negative consequences on data integrity within an app/database.
TL;DR: Either require an authentication token with every request or require authentication through a session.
Never trust users always. One potentially big issue is if you "hide" admin actions behind the admins page without requiring authentication.
For example, assume the backend server uses a REST API to accept commands. In the admin panel you get links to administrative actions like a button 'Delete Everything' that sends a DELETE request to server.net:8080/api/admin/everything without requiring any authentication. If you're a user, you can find that in the code potentially and then send a DELETE request to that address from anywhere without any repercussions.
We'd never give administrative privileges to anyone who would want to delete everything... Because we'll never untrust someone. Right?
Worse, someone might find the server and fuzz some inputs to it, and oops! They manage to delete everything (or even worse, GET everything stored in the database). This wouldn't be hard to do, especially if the server you use to authenticate is the same server you use to issue commands. History has proven "security through obscurity" to be a very bad paradigm. Every action should be authenticated, even if it seems like the actions will be hard to find.
Generally, providing a JSON web token or some other form of authentication token and having the user send that with every request is a good start at least, especially if it has an expiration date. The token would be provided through a separate request with valid credentials.
Sending a token with every single request obviously isn't ideal. There are a couple of other things to try. For servers using PHP, you can probably trust sessions (though very many people who know more than me would probably disagree). In more modern cases, you could try to use Web Sockets, requiring the token after connection. Then only after authentication with the token do you allow the user to make administrative requests.
That way, even if a user knows the exact command they can send to perform any action, the server won't let them without a current session or token. Unfortunately, unless you're already using Web Sockets or depending on a session, it will likely require a lot of changes. I'd consider this to be critical though.
It is always possible to tamper values in the front-end, there is no way you can rely solely on the front end to ensure security.
Your best approach is to implement some form of authentication and authorization on your backend. In this way, even is some users pretend to be admin, they will be blocked when you do the next request to the server.
Perhaps if you can send more information regarding your problem, we can think of a more specific solution.
I know this is probably an age-old question, but...are there any best practices for securing client secrets for performing OAuth2 authentication in AngularJS applications? I've been racking my brain trying to think of a solution to providing truly secure access to an API from modern style web applications (they need not necessarily be AngularJS.) In my experience, adding layers of abstraction and obfuscation really don't do anything to improve security...they just make cracking the security egg more difficult for any prospective hackers (however many of them prefer a good challenge, so all your really doing is just making the hack more fun.)
Aside from the obvious ineffective solutions such as obfuscation and convolution of code and things like that, are there any best practices for securing client secrets in modern day web applications? I know these questions arose with desktop client apps, and I don't believe there was ever a solution beyond "Might as well obfuscate, that'll slow hackers down". Are we in the same boat with web apps? Is there no real solution to this problem?
If there is not a solution...is there even really any point in securing REST APIs with OAuth?
Remember that OAuth is less about protecting against impersonation and more about protecting credentials. 3rd parties authenticated a user's identity for you without exposing the user's credentials. Since Tokens are not credentials, the amount of harm a hacker can do and his window to act are limited.
But OAuth is not inherently more secure for your application than regular username/pwd authentication. And on client-side apps, all your code is available for the world to see! As
you mentioned, client-side encryption is a questionable strategy.
While there aren't established best practices for protecting client interactions, here are some approaches to minimize your exposure:
1) SSL: Silver bullet? Maybe. The more you can use SSL in your site and your requests, the safer your users' requests will be. I honestly believe all privileged requests should be made by encrypted requests.
2) Short Token Life-Span: The shorter the life-span of your Token, the less incentive/advantage of sniffing it.
OAuth 2.0 creates a constant chatter out of authentication by exchanging Authentication Tokens for Refresh Tokens for Authentication Tokens. You, as the developer are now developing a chatty app that does a lot of "what's your token, here's another token, ask me for a token, here's your new token... so what do you want?" ... "oops, time's up, where's your Refresh Token?"
If that sounds like a pain, it kind of is. OAuth 2.0 is designed to make the process easier for you the developer. But the important point is, the shorter the life span of your tokens, the harder for a hacker to maintain a fraudulent identity.
Refresh Token reference
3) Enforce your Domain: Want to give sniffers less chance of abusing the chinks in your armor? Don't allow Cross Domain Requests!
Sure, we often have distributed environments. But if your Facade is on the Client's Domain, your exposure is lessened (word choice questionable).
Force the hacker to use your domain, limit their creativity.
4) Use 3rd party API's for maintaining you access as often as possible: Google and Facebook API's and Services have been unit tested, battle tested, and evolved. The more you can lean on them to maintain your user's Identity, the less work you will do and fewer chances you take.
5) Check IP addresses: Almost anything can be faked, but the hacker must know that IP Address is part of your validation. This is the least assured of all practices, but combined with 1,2, or more, the gaps for hackers to exploit get smaller and the payoffs for effort fade.
6) Use a "Secret" or 2nd parameter: You can pass your users more than tokens. You can pass your own Alter-Token.
Pretend it's an ID data being passed back and forth. Name the param in a non-obvious way. Make it a number (e.g. age, height, address). The important point is, your hacker knows little or nothing of what's being asked for on the other side!
You can throw a serious monkey-wrench by having 3 params that act as security.
7) Don't give error messages to inform the hacker they've been caught. Give timeout msgs rather than "Got You!" If the invaders don't realize the fraud was caught they don't adapt as well.
I can't say it enough -- SSL saves a lot of trouble.
Note: All client Providers I have seen allow access to their API's without exposing Secret. Secret should never be exposed on client.
Any data exposed on client can be gleamed
Any encryption algorithm you use, will be exposed on the client.
I came here looking for the answer to this very question - how to handle the secret/id in an SPA. I came up with my own solution that hides the secret in the server but I wanted to confirm what I was doing was best practice. So since answers avoid this I will explain my flow in hopes that it will help anyone out there.
Our architecture - we have a ruby server as the api server and an express server serving up the Angular app.
Normally all communication is simply done RESTfully thru the api so the node server is just serving static files and not really doing a whole lot.
Since we were at the point of implementing the login/signup flows I came across the - what was new to me - OAuth 2.0 flow of how to handle things.
Before we can make any requests to the server and the server will take us seriously we need to get ourselves the Bearer token. I chose to implement it as a node endpoint thus to hide the client secret inside the node server itself.
So our customer has entered all their juicy data and are redy to become a user in our app they hit the submit button.
The app fires the request to the node server to get ourselves a yummy token that we can use as the Bearer. I chose to pass the client id as a GET request query parameter. First off I had both client id and secret in the node server but it felt like the id could/should be on the, well, client. So I went with this way.
The node server receives the client id thru the GET request and then proceeds to fire the POST to the host(ruby api). Constructing the url + grant type + client id + client secret. Thus hiding the implementation from the world.
The ruby server return a token for us to use which we then return to the client that initialized the signup request.
The SPA now has a Bearer token which we can use in the header of the signup request.
Thus completing our flow and having a hidden cient secret from the world.
Since we have a token with a certain lifespan we also have a request error interceptor that will catch tokens that have expired and thus make a new token request and then refire the failed call.
I have chosen to use on the Angular side of things this lib for users flow.
https://github.com/sahat/satellizer
Its a super handy lib that gets all the boring boilerplate code that has to be written every time we want an app to have authentication thru email/password and also thru oauth....very handy.
So since this is my own interpretation of how to do such things - feedback is kindly requested.
I want to write a program that analyzes your fantasy baseball team and notifies you of recommended actions, possibly multiple times per day. The problem is, you aren't playing fantasy baseball on my site, you're playing on yahoo, or cbs, or espn, etc.
On the majority of these sites, fantasy teams and leagues are not public, so you must be logged in and a member of the league to see the teams in the league.
All that I need is the plain html for the team page on each of those sites to be sent to my server, where I can then parse and analyze the file and send user notifications.
The problem is that I need username/password combinations to easily get this data to my server when I need it, and I think there will be a lot of people who wouldn't want to entrust their yahoo/espn/cbs password to me.
I have come up with several possible ways to solve this problem:
The most obvious way is to ask for their credentials for the site on which their team is hosted. Then I could just programmatically log in and request the data I need. I'm guessing a number of people would be comfortable giving me their credentials, and a number of them not so much.
Write a desktop client, which the user then downloads. The client would require their credentials, but it could then basically do exactly the same thing that the server based version would do, log in, request the page, and send the page back to my server. The difference being that their password would never need to leave their desktop. Their computer would need to be on, and this program running for this method to work.
Write browser add-ons that navigate to the page I need, use the cookie that is saved from a previous login to login to the site, and send the page back to my server. This doesn't require my software to ever ask for their password, but if the cookie expires I am hosed, and I don't know much about browser add-ons besides.
I'm sure there are other options, but these are what I've come up with so far.
I have two questions:
1. What are the other possibilities for this type of task?
2. Am I over-estimating people's reluctance to give me their yahoo (for example) password? Is option (1) above the obvious choice?
It was suggested in the comments that I try yahoo pipes, and that looked like a promising suggestion so I explored it a bit. Having looked now at this, I don't think that is an option. So, it looks like I'll be going with option 1.
This is a problem I grappled with a couple of years ago when I wanted to do the same thing. Our site is http://benchcoach.com and the options we were considering were the following:
Original we considered getting the user's credentials and login. We would then log in and scrape their league and team info. The problem there is that after reading several of the various terms of service, this would definitely be violating the terms of service. On top of this, Yahoo! was definitely one of the sites we were considering and their users have email (where we could get access to sensitive data), and Yahoo! wallet. In addition, it would be pretty trivial for Yahoo/ESPN/CBS to block our programmatic logins by IP Address.
The solution we settled on (not 100% happy but it does seem to work) was asking our users to install a bookmarklet (like delicious, digg or reddit) which would post the current html page to our servers, where we could parse the data and load our database. If they were still logged into their Yahoo/ESPN/CBS account, we would direct them directly to the pages, otherwise, those sites would prompt for authentication. Clicking the bookmarklet once more, would post the page to our servers.
The pros of this approach was that we never collected anyone's credentials so any concern of security would have been alleviated. Secondly, it would make it impossible for Yahoo/ESPN/CBS to block access to our service since we would never be connecting directly to their servers but rather the user's browser would be posting the contents of their browser to our server.
The problems with this is that it takes 2 clicks to post a page to our site. For head to head leagues, we needed 3-4 pages so it would take our user 6-8 clicks to sync their league to our servers. We're still looking at options for this.
One important note is that I ran into the product manager of the Yahoo Fantasy Football site at a conference a year ago. We talked about how we were getting the Yahoo data, and he confirmed that getting credentials would violate their TOS and they may stop us. While I don't think they would have, it would have made it hard to invest time and energy to develop this only to have them block our site and pissing of users by closing their accounts.
A potentially more complicated answer could possibly be done with (for example) yahoo pipes.
Hypothetically, you create a pipe which prompts the user for their credentials and provides them with a url which contains their scraped data. They enter this URL in their site, and never have to provide their credentials directly. Even better, for the security-conscious, it would be possible to examine what the pipe was actually doing before entering any information.
The downside would be increased complexity (as well as you'd have to write and maintain the pipe). Having said that, you could provide a link directly to the published pipe from your site, to make things as easy as possible.
Option 1 is the obvious choice. People who trust your site will provide the details. There is no other way you can login to other site while screen scraping.