I have built a JavaScript/CSS/HTML component with the help of ChatGPT, which I’ve placed inside an HTML element. The component is a spinning Lucky Wheel that uses an SVG image as the wheel with prizes, etc.
My issue is this: to spin the wheel, the user needs to have tickets. In my workflow, I’ve set it up so that if the current user’s ticket count is 0 or less, the workflow won’t run. If the user has at least 1 ticket, the workflow proceeds, one of the steps runs the JavaScript function luckywheel_spin();.
Since I have no real experience with JavaScript, I accidentally discovered that I can execute this function manually in the browser console just by typing luckywheel_spin();… and the wheel runs and workflows follow (When a value in JavaScript to bubble event)
So my question is: what is the best way to secure this?
You can’t secure anything that happens in the browser.
You can improve it slightly by adding a check in the luckywheel_spin() function itself to check the number of tickets, so it only runs the code if the number is more than 0.
But that’s still NOT secure - as it’s easy for a savvy user to either modify the code itself OR manipulate the client-side data, and change the number of valid tickets in the browser.
But at least it would prevent the wheel from spinning simply by invoking the function in the console.
But what you can (and should) do is secure whatever sever actions run after the wheel is spun, to prevent them from happening if no valid tickets are present.
Ahh yes that is one way to do it, thanks! it is possible to move all the JS to server side and just have the HTML and CSS on the client side and then call it from a workflow? or can people still bypass that? That way the JS is not visible i guess? But maybe someone can see it still if the intercept it?
No — JavaScript is a client-side language that runs in the browser (Node.js not withstanding, but that’s not relevant here).
But regardless, anything that runs in the browser can be seen, modified, or bypassed by the user — that includes JavaScript, HTML, CSS, and even any data loaded into memory (such as how many Tickets the Current User has)..
So it doesn’t matter how or where you check whether the user can spin the wheel (on the sever or in the browser) — the fact that the spinning of the wheel happens in the browser means it’s inherently exposed and can be manipulated.
That’s just the nature of the web: the browser is never a secure place for logic that controls rewards, prizes, purchases, discounts, or anything of real value . That logic must be enforced on the server.
Dang… So i can move all the JS to the server side and then send the result to the client side? If this is Yes, do i need to set up API calls etc and make it complicated or is it just as simple as running the java script in the workflow and then returning the value?
Edit, i saw you said no to that idea… not sure how to solve it then
Well you can’t use your current javascript on the server - but you should indeed move the logic for determining the prize to the server (whether using standard Bubble functionality, a node.js script, or some other sever language via an external API - although it can probably done entirely with vanilla Bubble functionality - no need for any custom code), and then return the result to the client.
But understand this - as soon as the result gets returned to the client (i.e. to the browser) it can be manipulated (i.e. changed).
So if your server actions determine that the prize is $10, and sends that to the browser, a savvy User could change that to $1m (but only on the browser).
So, your actual process/logic for paying out the prize MUST be based on the server logic (which is secure) and NOT on the client-side data, which is NEVER secure.
Thank you so much @adamhholmes !! I think i found a solution with the plugin random number picker and then some server side logic, i will send an update when i think i have gotten it working. Bonus is that random number generator is done on server side says the plugin code
Hi again @adamhholmes and anyone who might stumble across this later.
Per Adam’s suggestion, I moved all the logic to a server-side workflow. When the user picks a prize, the workflow creates a new Lottery Prize object (an option set) like so:
Display: White Shirt
ID: WS
(other fields as needed)
On the client I just trigger the wheel with:
luckywheel_spin(
"Result of step 3 (Create a new Lottery Prize)'s ID"
);
The wheel appears to spin randomly, but it always lands on the prize the server has already selected.
Note: Folks can still run the spin function from the browser console if they know how to; the wheel will spin, but without the server-side workflow they won’t receive any reward.
I might create a detailed post on how to build the lucky wheel and i will post it here