I was testing the security of my app and I started messing around with the Meteor.defineSetter function that is accessible in the browser.
Here is code:
Meteor.userId()
Output:> ‘stringidXXX’
Meteor.defineSetter(‘test’, function(val) { this.userId = () => val})
Meteor.test = ‘spoofedUserIDXXX’
Meteor.userId()
‘spoofedUserIDXXX’
Meteor.call to the server doesn’t update with the fake Id but the client does and data updates according to the state of current userId.
For this part of my code is calling a refresh of the state of the page and updating the according to the fake values:
const [now, setCountdowns] = useState(null)
useEffect(() => {
const interval = Meteor.setInterval(() => {
setCountdowns(Date.now())
}, 100);return () => {
Meteor.clearInterval(interval);};
}, [now])
{Meteor.userId() ? <div>{Meteor.userId()} logged</div> : <div>not logged</div>}
When spoofing the UserId, the data updates and prints “logged” after the first rerender that occurs on the setCountdowns update.
A simple way to avoid the problem is to never use Meteor.userId() directly in the render function but instead declaring a hook and checking it’s value like this:
const [user, setUser] = useState(Meteor.userId()? true: false);