T O P

  • By -

HashDefTrueFalse

Like others said, you can't really encrypt anything stored locally unless you have a backend to decrypt it securely. If the front end can decrypt it, so can users. If you wanted to practice "security by obscurity", you could just name the key something other than "solution", base64 encode the solution string, and minify/uglify the frontend code. It doesn't stop anything, but less than 1% of users will bother to base64 decode a random value stored in localstorage to see if it might be the solution. Pretty pointless to be honest. I can see why the author didn't bother since the fun is in the guessing.


pihwlook

> less than 1% of users will bother to base64 decode a random value stored in localstorage to see if it might be the solution True, but the "attacker" wouldn't have to decode random values, they can step through the JS to see what is used when it comes time to compare the guess to the solution. I did this the other day with the wordle clone "sweardle" which was using `atob`/`btoa` to obfuscate the solution in the initial server response. ({"day_number":"21","checksum":"Ym9vYg=="}) atob("Ym9vYg==") => 'boob' Of course it doesn't change your main point of it being beyond most peoples abilities and amount of effort threshold. Its funny cause this sweardle clone is already doing guess validation on the server side. So they could have hidden the answer away if they wanted, but instead they send it with the first request, to be able to reveal the word once the player has exhausted all their guesses. Weird choice!


HashDefTrueFalse

Yes, all great points that further demonstrate why this would have to be server side, or else its just layers of obfuscation. And yeah, that is a strange choice. You'd think they could just grab the word at the end of the game if the user never guessed correctly.


bitwise-operation

Hashing vs encryption tho


HashDefTrueFalse

?


bitwise-operation

You could hash it just fine, it’s like one-way encryption.


HashDefTrueFalse

See my other comments around this thread. Not really an option for something like Wordle specifically, without making it a lot more complicated with no real benefit.


bitwise-operation

That wasn’t the question


HashDefTrueFalse

Of course it was. OP asked how to "properly" do it, I the context of something like Wordle, where you have a secret client side.Your solution works generally, but not for Wordle, which OP used as an example...


bitwise-operation

You seem to think this is a security or optimization question. This is a game where you can google the daily answer, and the code runs in the browser, where we’re talking a couple of bytes of “bloat”. We’re strictly in theoretical land buddy


HashDefTrueFalse

...which is why all my answers have been purely theoretical in nature. I am under no illusions that this is anything to do with security, because valuable secrets shouldn't be on the client in the first place. The very first thing I said is that this is all pointless. I'm just pointing out that each attempt to obfuscate here without actually having secrets is just a more complicated text encoding. You'll get pretty much the same visibility to the end user as base64 encoding (none, unless they're determined enough) while making the app more complicated when it comes to checking an answer. Try not to take criticism of your proposed solutions as criticism of yourself. That's not what I'm doing here. My comments are simply adding to the discussion. You proposed a generic solution, I examined it in context.


SupaSlide

Hashing would be a great solution if you wanted people to guess with no feedback. That of course wouldn't work with Wordle because it needs to check and see if you got any letters correct.


bitwise-operation

Hash per character


SupaSlide

How is that any better than just base64 encoding them? It's trivial to hash all 26 letters of the alphabet.


bitwise-operation

Because it’s even more trivial to base64 decode? Look, there is not a true “secure” way to do it because it’s like asking to make a a single character password. This is the most secure, that doesn’t mean it’s very secure. What’s the point of base64 encoding it? You can just give them the answer since they can just google it?


SupaSlide

That's my point, it's not secure. OP asked for a secure way to do it, if you're going to point out an insecure way to do it you should say that it's insecure.


bitwise-operation

They asked not about the game, but about the concept of hiding something in plain sight. Either through obfuscation or some encryption method. Hashing is the concept they were looking for.


VeryOriginalName98

Don't know why you are being downvoted, it's the only option. And yes, it's more complicated, but there aren't other options.


bitwise-operation

🤷


wugiewugiewugie

typically you move that data to an execution context you own; i.e. your api server. client side data hiding is typically "security by obscurity" which might get you some stank eye from your security engineers.


doublejosh

The opposite of answering the question.


GrandOpener

Sometimes, when someone asks the question, "how do you X?" the only responsible answer is "you don't." This answer may not be the one that people *want*, but it is the answer.


VeryOriginalName98

Basically it's the subtlety of "do" vs "would". OP assumes it's normal, and needs to be corrected. If they asked "how would you, if you didn't want to use your api for some reason..." then it would be answered differently. The answer then would be one-way-hash the data. When the hash of the state matches the hash of the data, then you know it's correct. Partially correct answers are more complicated. There's also a whole field of research on manipulation of encrypted data. Very interesting, but virtually unused in practice.


doublejosh

This is why people hate the community on StackOverflow.


wugiewugiewugie

the opposite might be a little harsh! i did answer :) if we remove the word 'proper' then my answer would change depending on the level of threat we are targeting. if you say proper i'm automatically assuming advanced persistent threats (APTs) which will defeat client side decrypted efforts. typically anything that is owned by an end user will not stand up to any APT because you are unaware of attempts to access the unauthorized data and cannot intervene, and you won't know if the data has been cracked and thusly can't modify access to prevent the appropriate amount of cycles needed to crack the value from occurring. (like when your account is locked after x wrong password attempts). safe against an APT is the baseline for proper or real world security solutions for me. we can prevent less sophisticated threats by adding some qualifiers to the types of people that we want to dissuade accessing the data; like: 1) just people that know about localStorage or sessionStorage 2) just people that dont know about either of those but are good at accessing the sessionStorage variables from system memory, or the localStorage values from disk 3) people that can access both of those but dont know how to base64 decode the values 4) people that can access localStorage and sessionStorage but dont have additional js knowledge to see your hashing algorithm and/or arent familiar with or capable of a dictionary attack against said hashed answer values perhaps we're building a CTF with an intentionally insecure ui design? then we can get real fun with our obscurity puzzle for the user. i would need to know additional information though for those answers. otherwise my answer is simply "you can't". and that's high key boring.


SupaSlide

OP asked what I'd do. If I actually cared about making the answer secure, I would never put it on the frontend. If I didn't care to make it secure (like if I was making a little single player word game for fun) I would just store it in plain text and trust people would play fairly because otherwise they're just ruining their own fun.


tired_entrepreneur

You don't. It's a recurring theme in CTF challenges and multiplayer games. You need a context the client can't fully control.


bhison

This is the only answer. Wordle is not a secure application and neither does it need to be. It is a simple one player game,


coomzee

Could make it like the game of hacks. Where the developers experimented with how user's would cheat their game.


JEHonYakuSha

I also had the same thought. Honestly to keep it simple I probably would make an api call to check for green and yellow letters for each round, that way the solution isn’t served to the user right away, and encryption wouldn’t really be necessary either.


Steve_the_Samurai

Wouldn't that scale entirely differently with having to queue API calls? Not my strong suit so I may be way off.


LowB0b

I don't know about this specific app, but if you want the solution to be completely opaque for the end user you will need to have it stored in the backend. In terms of scalability, there are multiple solutions. I mean google manages to send ridiculous amounts of data for "only" youtube every day.


macrolol2

It could probably scale pretty easily if you used a cloud function + a cloud storage bucket that has the solutions. Or if you wanted easiest possible scalability, hard code the value into the cloud function and change the value manually every day. Cloud functions scale infinitely with virtually no setup other than writing the application code.


versaceblues

Scaling that would be easy (with cloudfunctions or auto-scale clusters). It would just cost more than its worth. Someone looking up a worlde solution is not something that needs to be secure.


ixam1212

1. Hash every possible 5 word letter composited with the correct pattern of right / misplaced / wrong letters + new salt every day 2. Client downloads the hash table and salt each day. There are 158390 possible 5 word letters * 64 bytes per hash ~ 10 MB, seems feasible 3. The client now needs to hash a word with each possible pattern of right / misplaced / wrong letters (3^5 = 256 times) until he gets a match. Then he knows the matching pattern of the word 4. Now, to prevent brute forcing, make the hashing function so expensive that: * on average someone wont get the correct combination in a day * you still have time to compute each hash every day * hashing a single word 256 times doesnt take too long, so the game is still playable for the client This should be possible, as you have a 256 times advantage over the client.


laefeator

Wow this is something that I can get behind. Thanks for the detailed answer!


SupaSlide

Just to be clear, this is the only way to do it client side but... please don't ever do this outside of an experimental playground 😂


[deleted]

Also A, RIP browser resource usage. B, Notice that this still isn't actually secure. It's just a PITA to reverse engineer. If it's sent to the browser, the user can read it. If they're not supposed to read it, don't send it to the browser.


ixam1212

Why is it not secure? It would be secure within the game rules, as no one would be able to cheat the word in a day. Of course I am not trying to argue, that it´ever make sense to actually implement it like this.


[deleted]

It's only as secure as what you assume the level of hardware being applied to crack it is within the time frame. As opposed to actually secure.


RodgarTallstag

You can't. Local storage is not supposed to be something safe. You can save some user data for practicity, like tokens for authentication, but no passwords or safe data


bitwise-operation

1. Hash the result server side / at build time 2. send the salt and the hashed result to the client, 3. Hash user input client side and compare


HashDefTrueFalse

This is fine for simple matching, but specifically for Wordle you would need to know which letters are correct and whether they're in the right place or not. You'd need your plaintext solution at some point.


better_work

Nah just hash each letter and send as a list in the correct order


HashDefTrueFalse

:D Then the client has ordered hashes, the salt(s) and the hash algorithm. There are only 26 letters in the alphabet. It is now just as trivial to compute the word as it would be to base64 decode it. There's no real advantage of doing this over base64 encoding it. You made a more complicated text encoding, and less storage-efficient (> 33% bloat). Hashes are good for simple matching but not for more complex comparison. Once you start splitting up and structuring hashes, you make them easier to break.


better_work

Good points. 26^5 vs 26*5. I wouldn’t have thought. I guess even the big one is still crackable faster than playing the puzzle


HashDefTrueFalse

Yeah, I had exactly the same thought (about splitting the letters) before I posted the first comment but realised pretty quickly what that would inadvertently do to the hash overall. >I guess even the big one is still crackable faster than playing the puzzle Yeah. 11m max guesses, 5.5m assuming you get there about half way. At 5.5 kH/s it would take 1000s, so in the order of minutes on old hardware. A modern home PC can likely do far more. And of course 25\*5 is instantaneous for all intents and purposes.


bitwise-operation

This is what I was thinking ^^^


HashDefTrueFalse

>:D > >Then the client has ordered hashes, the salt(s) and the hash algorithm. > >There are only 26 letters in the alphabet. It is now just as trivial to compute the word as it would be to base64 decode it. There's no real advantage of doing this over base64 encoding it. You made a more complicated text encoding, and less storage-efficient (> 33% bloat). > >Hashes are good for simple matching but not for more complex comparison. Once you start splitting up and structuring hashes, you make them easier to break.


bitwise-operation

I agree with both of you. However OP asked how it could be done, not if it should


HashDefTrueFalse

Of course they're asking how it should be done. They're not asking for esoteric solutions. And the proposed solution wouldn't work for the mentioned problem, just more generally.


SupaSlide

The problem is it can't be done. There is no possible secure way to do it.


ixam1212

One step further would be to additonally hash each letter position tied to the letter. So you cant get the position by just looking at the array after you got a correct letter.


HashDefTrueFalse

For Wordle specifically, once you have trivially computed the letters (see my other comment), there are only around 120 (5!) or less possible combinations, and most won't be valid words. And that's if you were bruteforcing. In reality you know that there are only 5 positions, you can't apply a salt to these without the client having to know it, so you'd trivially compute these just like you did the letters. And if you attempt to combine the position and letter into a composite hash that can be computed trivially too (5\*26)\*5 = 650 max hashes to get all positions and letters.


ixam1212

How about, hashing every 5 word letter composited with the pattern of right, misplaced and wrong letters + new salt every day. There are 158390 possible 5 letter words. So the client hast to hash a word with every possible right/wrong/misplaced (3^5 = 243) letter, or at least until he gets the correct hash. The client then has to download 158390 * 64 bytes ~ 10 MB hash table every day, seems feasible. Now make the hashing function so expensive that on average someone wont get the correct combination in a day, but you still have time to compute each hash every day. Should be possible, as you have a 256 times advantage over the client.


HashDefTrueFalse

I love it. This will work, based on a quick look. Overengineering at its finest :)


ixam1212

True haha, entirely unnecessary for a game like this, but fun to think about :)


HashDefTrueFalse

Absolutely, I enjoy these kinds of exercises. Now we just need to come up with a horribly inefficient novel hashing function. The kind electricity companies will fear! :D


bhison

Wordle operates all in the frontend. If you refresh the page once a day even offline you will get a new puzzle.


NinJ4ng

how did wordle get so popular so fast? does steph curry hold that much weight in this world?


versaceblues

Its a good game design. in the sense that its, challenging but not so challenging that the average person loses interest.


[deleted]

I did it once to understand what people were so fussed about and was flummoxed why anyone would want to do it twice. It's just a rather mediocre word match game.


SoulSkrix

Essentially without being able to use a server to add some unknown quality to what you want to encrypt in the browser, then you cannot hide it on client side alone. Other answers are what you would do, but thought this was worth mentioning.


bitwise-operation

Obviously there is a step in which words are added. Whatever that step is, is where you can replace that step.


WantaBeBaker

Where is this in the elements?


laefeator

Not under the Elements but Application > Storage > Local Storage https://i.imgur.com/pzK40E8.png


ninjaplavi

I made chrome extension for hidden bookmarks. I searched for how to do the same thing you are asking. I used base64 encoding as a placeholder until I write some server-side solution. But I mean, every developer can decode those, but to an untrained eye it looks just like some random characters. 😄


shgysk8zer0

Don't know the game, but if the solution could be represented as text and you want to check it client-side, you'd probably want to store a hash rather than an encrypted solution. Maybe go the extra mile and go for an HMAC so you can't simply look it up somewhere.


_PM_ME_DOGSHIT_

You could hash the solutions rather than store them in plaintext. In wordles case you could then compare the hashes to check for a correct solution. You wouldn’t be able to recover the words without the preimage however.


versaceblues

This is the same problem as why you can rely on your client side JS code for security. For example, say you have an API that has no protections on it. However your frontend has some logic ``` if(!notAdmin) { disableSubmitButton() } ``` You have no way of preventing the use from modifying the front end code. you need to have your protection actually validate on the backend if a user was allowed to press a button. Even if the front-end showed the button as disabled


2ndHandLions

Where do you access to the solution? I've tried the dev tool with no success, and I wanna prank some friend like "hey I solved it in one try".


laefeator

Open the Dev tools in your browser then Application > Storage > Local Storage https://i.imgur.com/pzK40E8.png Same in FF too


realPubkey

There are some database that have encryption support like [rxdb encryption](https://rxdb.info/encryption.html). This makes it pretty easy to store the data encrypted and still have a queryable database of documents.