I am implementing a simple user authentication system using react js and node js api. This is what i am doing inside ComponentWillMount method :-
1.checking if the token exits (in localStorage)
2.if it doesn't exits then the value of state 'token' will stay blank
3.if it exists then checking if it's valid using an request to backend.
4.If the token is valid then state 'token' as localstorage.token
5.If the token is invalid then the value of state 'token' will stay blank
inside render method i have added conditional rendering based on the value of state 'token' i.e. if the state 'token' is blank then normal page will be rendered else it will be redirected to user's page.
The problem is i can change the value of state 'token' using any react developer tool. And that is causing a loophole to login using a fake token.To avoid that i have to check for the validity of state 'token' everytime it is changed using one of the life cycle methods like ponentDidUpdate shouldComponentUpdate . But as mentioned in the official documentation of react
shouldComponentUpdate only exists as a performance optimization. Do not rely on it to “prevent” a rendering, as this can lead to bugs.
Using ponentDidUpdate isn't useful as it will be called after ponent will already be changed due to state change.
Using ponentWillUpdate is mentioned as Unsafe in the official documentation
I am not sure how can i tackle this loophole. Here is the code for the ponent
import React,{Component} from 'react';
import {
BrowserRouter as Router,
Route,
Link,
Switch,
Redirect
} from 'react-router-dom';
import Home from './Home';
import Nav from './Nav';
import Login from './Login';
import Signup from './Signup';
class Out extends Component{
constructor(){
super();
this.state = {
token : '',
isLoading:false
}
this.isLoading = this.isLoading.bind(this);
}
logout(){
alert('logged out');
}
ponentWillMount(){
let {match} = this.props;
this.navNoSessionRouteData = [
{to:`${match.url}login`,name:'Login',key:'r1'},
{to:`${match.url}signup`,name:'signup',key:'r2'},
{to:`${match.url}`,name:'Home',key:'r3'}
];
this.navNoSessionButtonData = [];
this.setState({
isLoading:true
});
const tokenVar = localStorage.getItem('token');
if(tokenVar == null){
console.log('not logged in');
this.setState({
isLoading:false
});
}else{
fetch('http://localhost:3000/api/account/verify?token='+tokenVar)
.then(res=>res.json())
.then(json=>{
if(json.success){
console.log('logged in');
this.setState({
token : tokenVar,
isLoading:false
});
}else{
this.setState({
isLoading:false,
});
}
});
}
}
isLoading(){
let {isLoading,token} = this.state;
if(isLoading === true){
return (
<p>Loading...</p>
);
}
else{
let {match} = this.props
console.log(token);
return(
<div>
{
(token)?<p>Logged In</p>:(<p>NOT logged IN</p>)
}
<div className = "row">
<Nav navRouteData = {this.navNoSessionRouteData} navButtonData = {this.navNoSessionButtonData}/>
</div>
<div className="row justify-content-center">
<Switch>
<Route exact = {true} path={`${match.path}`} ponent={Home} />
<Route path={`${match.path}login`} ponent={Login}/>
<Route path={`${match.path}signup`} ponent={Signup}/>
</Switch>
</div>
</div>
)
}
}
render(){
return(
<div>
{this.isLoading()}
</div>
)
}
}
export default Out;
I am implementing a simple user authentication system using react js and node js api. This is what i am doing inside ComponentWillMount method :-
1.checking if the token exits (in localStorage)
2.if it doesn't exits then the value of state 'token' will stay blank
3.if it exists then checking if it's valid using an request to backend.
4.If the token is valid then state 'token' as localstorage.token
5.If the token is invalid then the value of state 'token' will stay blank
inside render method i have added conditional rendering based on the value of state 'token' i.e. if the state 'token' is blank then normal page will be rendered else it will be redirected to user's page.
The problem is i can change the value of state 'token' using any react developer tool. And that is causing a loophole to login using a fake token.To avoid that i have to check for the validity of state 'token' everytime it is changed using one of the life cycle methods like ponentDidUpdate shouldComponentUpdate . But as mentioned in the official documentation of react
shouldComponentUpdate only exists as a performance optimization. Do not rely on it to “prevent” a rendering, as this can lead to bugs.
Using ponentDidUpdate isn't useful as it will be called after ponent will already be changed due to state change.
Using ponentWillUpdate is mentioned as Unsafe in the official documentation
I am not sure how can i tackle this loophole. Here is the code for the ponent
import React,{Component} from 'react';
import {
BrowserRouter as Router,
Route,
Link,
Switch,
Redirect
} from 'react-router-dom';
import Home from './Home';
import Nav from './Nav';
import Login from './Login';
import Signup from './Signup';
class Out extends Component{
constructor(){
super();
this.state = {
token : '',
isLoading:false
}
this.isLoading = this.isLoading.bind(this);
}
logout(){
alert('logged out');
}
ponentWillMount(){
let {match} = this.props;
this.navNoSessionRouteData = [
{to:`${match.url}login`,name:'Login',key:'r1'},
{to:`${match.url}signup`,name:'signup',key:'r2'},
{to:`${match.url}`,name:'Home',key:'r3'}
];
this.navNoSessionButtonData = [];
this.setState({
isLoading:true
});
const tokenVar = localStorage.getItem('token');
if(tokenVar == null){
console.log('not logged in');
this.setState({
isLoading:false
});
}else{
fetch('http://localhost:3000/api/account/verify?token='+tokenVar)
.then(res=>res.json())
.then(json=>{
if(json.success){
console.log('logged in');
this.setState({
token : tokenVar,
isLoading:false
});
}else{
this.setState({
isLoading:false,
});
}
});
}
}
isLoading(){
let {isLoading,token} = this.state;
if(isLoading === true){
return (
<p>Loading...</p>
);
}
else{
let {match} = this.props
console.log(token);
return(
<div>
{
(token)?<p>Logged In</p>:(<p>NOT logged IN</p>)
}
<div className = "row">
<Nav navRouteData = {this.navNoSessionRouteData} navButtonData = {this.navNoSessionButtonData}/>
</div>
<div className="row justify-content-center">
<Switch>
<Route exact = {true} path={`${match.path}`} ponent={Home} />
<Route path={`${match.path}login`} ponent={Login}/>
<Route path={`${match.path}signup`} ponent={Signup}/>
</Switch>
</div>
</div>
)
}
}
render(){
return(
<div>
{this.isLoading()}
</div>
)
}
}
export default Out;
Share
asked Oct 8, 2018 at 9:42
Vaibhav VermaVaibhav Verma
1472 silver badges11 bronze badges
9
- Since a fake token wouldn’t work anyway is there actually a problem? A token needs to be stored somewhere and the user can change it however it’s stored. – Sami Kuhmonen Commented Oct 8, 2018 at 9:47
- I am not even sure this is a loophole. Worst case scenario the user will mess with his own token and will need to authenticate again. – nikos fotiadis Commented Oct 8, 2018 at 10:01
- it's a problem if i want to provide some services that i want to be accessible only to logged in users and those should stay hidden for the fake token – Vaibhav Verma Commented Oct 8, 2018 at 10:03
- any user who is not logged in can add any value to state 'token' and will be able to see the hidden content . – Vaibhav Verma Commented Oct 8, 2018 at 10:04
- 3 Well if you are going to accept any token, since they are fake, you can't really stop them from doing this. If you store information in the client-side not matter how you do it a determined user will find a way to alter it. – nikos fotiadis Commented Oct 8, 2018 at 10:26
1 Answer
Reset to default 4Just to loop in here, I would answer this in two questions:
(I think closer to your question): If I can edit React state variables, how is anything I display secure?
The point here is they CAN navigate to UI that requires them to be signed in, but when they actually go to request data (either to your backend, or directly to your database like Firebase) then they will need a valid token to do so. Your backend should be checking for this, and won't return any valuable data.
If I can read React state variables, how safe is my token from being stolen and used by someone else to request and write data?
For this, see this answer