-
Notifications
You must be signed in to change notification settings - Fork 850
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Hashes for Slots in ScriptableObject should be seeded #290
Comments
maybe useful lib if you want to find some collisions; (I guess you need to modify the hashing algorithm) |
Thanks -- that's an important issue. There seem to be very few people able to work actively on Rhino right now. This looks like a great issue for a new author who might be looking for a way to contribute to a new project. |
I started with including a public domain Java-aware (chars != bytes) port of MurmurHash3: https://github.com/botic/rhino/tree/issue290-seededhashes Various versions with more or less adaptions of the implementations can be found all over Github. Just some of them: Feedback / other ideas welcome, since this is the first time I work directly on Rhino ;) |
@botic What's stopping you from creating a PR from this? I think your approach is sound. I was just about to do this work myself when I saw you had done it already. |
It'd be great if either of you could do this!
At any rate, I'd prefer to see two more things:
First, the seed for the hash should come out of SecureRandom. That'll
increase startup time a bit but the vast majority of things that embed
Rhino already have the default instance of that initialized I bet, and
since the whole point of this is security we should do it securely ;-)
Second, I'd prefer to see the hash algorithm in a separate class since
ScriptableObject.java is so gigantic already. Bonus points if we have a
unit test for the class that at least verifies that the basic code paths
execute...
…On Mon, Aug 14, 2017 at 5:13 PM, Jeremy Whitlock ***@***.***> wrote:
@botic <https://github.com/botic> What's stopping you from creating a PR
from this? I think your approach is sound. I was just about to do this work
myself when I saw you had done it already.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#290 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAf0a38-ngxH8XLOMgz7lKRHhXI1Xx4wks5sYOLGgaJpZM4LQJvC>
.
|
Sorry to say, but my time is extremely limited right now. I see no time to do this in the next months due my parental leave and other projects. We implemented some workarounds in RingoJS and the web packages, which avoid the issue "good enough" for the moment. Afai-remember: some unit tests went red after my change and I could not spot the source of the problems. |
Here's an update on this issue. I've done two experiments so far: -- Used the contribution from @botic to use MurmurHash on every String object rather than the built-in hashCode() method on java.lang.String. Here are the results of the "v8 benchmarks" in these cases. (If you are new to Rhino then you will be shocked at how bad these are in comparison to V8 or even Nashorn): master: 88.8 One simple proposal would be to simply permute the hash that's generated in ScriptableObject.java by some sort of a random seed. For instance we could do the following:
I'm going to try this. I'm looking for feedback on the various pros and cons from a security perspective. |
Pull request #328 addresses this problem by dividing up the hash table that ScriptableObject uses into two implementations: One with very low overhead based on the existing code, and one that uses java.util.HashMap for its collision resistance. ScriptableObject changes from one to the other when the object reaches a threshold. (Currently 2500 properties based on some testing I did.) @botic -- thank you very much for bringing this to our attention. I used part of the test file you sent me to create a regression test. Please let me know if you have any issues with this. |
Pushed to master. |
Thanks, the approach sounds reasonable. Since most objects don't have 2.500 or more properties, attacks would run into the "trap". @gbrail no, perfect that it helped! |
As far as I can interpret the slot allocation in
ScriptableObject
it usesString.hashCode()
to generate a hash number, which then is used to determine a slot for the value. This makes it easy to exploit with an algorithmically attack.Take the following example in RingoJS:
For a 20 MB huge JSON with randomized keys it takes under a second to load. An attacker could use colliding hash codes since it's easy to generate them with the knowledge that slots are allocated with
String.hashCode()
. Just an example sequence of colliding hashes:AaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAa
,AaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaBB
,AaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaBBAa
, ……… Then the example above takes 20 minutes on my machine. And just imagine an application callingJSON.parse()
without any bounds for the request's body.To fix this problem Java changed its hash-based data structure's implementation with Java 7: https://vaskoz.wordpress.com/2013/04/06/java-7-hashing-drastically-better-than-java-6/
You can find the full code here: https://gist.github.com/botic/d409564dca727eea8086fb6a1cb00623
Further infos / links:
The text was updated successfully, but these errors were encountered: