14 ms·
PHP: md5('240610708') == md5('QNKCDZO')
- moonbug 11y agoIt's appalling to think that there are 'developers' who are still only now realising PHP's horrendous nature.
- dbrgn 11y agoJust to make it clear, I did not come up with this example. Unfortunately I can't find out the source anymore. It also contained some technical explanations about why this works. So if anyone remembers, I'd be happy if you could comment with the link.
- dbrgn 11y agoAh, here it is: https://twitter.com/spazef0rze/status/523010190900469760 https://twitter.com/spazef0rze/status/523010190900469760
- spaze 11y agoAuthor of the original tweet here, thanks for sharing! Here's the link to the "original original" MD5 tweet https://twitter.com/spazef0rze/status/439352552443084800 https://twitter.com/spazef0rze/status/439352552443084800 For similar tricks for SHA-1 and plaintext see https://twitter.com/spazef0rze/status/523010190900469760 https://twitter.com/spazef0rze/status/523010190900469760
- deleted 11y ago[deleted]
- Meekro 11y agoPHP's == has a lot of oddball effects. They were put in so that things would behave the way a novice expects them to (3 == '3') but would confuse more experienced programmers, or those coming from other languages. Unless you're deliberately taking advantage of automatic type conversion and whatnot, you should probably use === by default.
- EugeneOZ 11y agoDesigners of future languages, please take this example as a proof of the rule: don't design anything for newbies. They will find a way to make an error anyway, but dumbs-based design will be the problem for everyone else.
- troels 11y agoThat - and the error is going to be a lot more subtle and harder to find. In all fairness though, it's a balancing act - There are benefits to dynamic typing, but PHP clearly overdid it. (See also the disaster that was/is magic quotes)
- bencoder 11y ago> you should probably use === by default. unfortunately this can also backfire if your class/module is used in a different context where it gets strings instead of integers and you were just using === without really thinking about it: We had a case where the code was something like: function doSomething($value) { if ($value === 0) { //do something } else { //do something else } } This was then used in a slighly different context where $value was a string '0', it then ended up incorrectly in the //do something else block, doing the completely wrong thing. In this case the type co-erced == would have been better, and I think what the developer was expecting would be a type error due to the === but it's not a type error, it'll just fall into the else block.
- deleted 11y ago
- dietrichepp 11y agoI'm not exactly clear on how PHP == works, but you can see the MD5 for yourself: $ echo -n 240610708 | md5sum 0e462097431906509019562988736854 - $ echo -n QNKCDZO | md5sum 0e830400451993494058024219903391 - $ echo -n aabg7XSs | md5sum 0e087386482136013740957780965295 - All of them start with 0e, which makes me think that they're being parsed as floats and getting converted to 0.0. This is why "magic" operators like == in PHP and JavaScript never should have existed in the first place. Operators like == should be, by default, extremely boring. PHP's just happens to be a bit more magical even than JavaScript's.
- sigsergv 11y agoYou're right: % php -r 'var_dump("0e1" == "0e2");' bool(true)
- lars 11y agoThis, combined with the fact that you can increment strings gives some 'interesting' results: $a = "2d9"; $a++; echo $a . "\n"; $a++; echo $a . "\n"; Output 2e0 3
- ulrikrasmussen 11y agoThis is wonderful, I love it! Interestingly [1], this echoes "2e0" followed by "3" in hhvm-3.7.0, but "3" followed by "4" in hhvm-3.6.0. [1] http://3v4l.org/sJhP8 http://3v4l.org/sJhP8
- debacle 11y agoThat means that someone was using this "feature" in a relatively core piece of code from the PHP ecosystem. Enough that hhvm felt they needed to support it.
- jlouis 11y agoThere is some nasty type conversion going on here, from the type of stochastic random throws of two nine-sided dice to floats to integers. Where is your type preservation, PHP?
- est 11y agoOK, how did this happen?
- masklinn 11y agoPHP's `==` tries very hard (even harder than javascript's) to "please" the user. That means if if can it will fallback to converting both sides to numbers and compare that. Here all hashes are of the form "0e{digits}" which is a valid scientific notation, so when `==` internally converts them to numbers they're all parsed to `float(0)` and therefore equal, success!
- ck2 11y agoI looked at this and said "oh well, at least hhvm is consistent".
- nls 11y agoWell.. http://3v4l.org/tT4l8 http://3v4l.org/tT4l8
- rurban 11y agoReminds me on bash, where I also have to prefix values to compare with x, to be able to handle empty vars. if [ x$1 == x$2 ]; But automatic string to float conversion is just crazy, esp. in comparison context. Perl, which is equally soft, has at least numerical and string comparison operators. $ perl -e'print "0e462097431906509019562988736854" == "0e830400451993494058024219903391"' 1 $ perl -e'print "0e462097431906509019562988736854" eq "0e830400451993494058024219903391"' So the solution is to use === which does not compare references with strings but the values, or the strcmp function. And refrain from using == with strings at all. '0XAB' == '0xab' is true. Comparing any string to 0 with == will return true.
- viraptor 11y agoI'm not sure why does this crazy "x" prefix tale still continue. You can simply quote them instead. Especially if you use bash and not some other sh-compatible shell: if [ "$1" == "$2" ]; will work just fine. If you need all sh compatibility, it should be test for "x$1" anyway (still quoted).
- Arkanosis 11y agoI think you meant “=”, not “==” (though the latter would work with bash).
- viraptor 11y agoWell, either in the example. Parent was saying "Reminds me on bash" For sh version, I'd go with super-safe: if test "x$1" = "x$2"
- seanp2k2 11y agoIf you're doing that, even better to use "x${1}" to be safer. Also, conditional expressions ( [[ instead of [ or `test`) are generally a bit more well-behaved. See http://wiki.bash-hackers.org/syntax/ccmd/conditional_expression http://wiki.bash-hackers.org/syntax/ccmd/conditional_express... for more info.
- shubhamjain 11y agoPHP's type coercion is nothing like I have every seen in any other language. Its horrendously messy, ugly and completely inexcusable. Strings type-casted to integers are 0. Seriously? Take a look at this, > $arr = array(0, "was", "invented", "in", "india"); > var_dump( in_array("Hello", $arr ) ); and yeah it is TRUE because "Hello" got coerced to 0. I blogged about a major bug, I faced, in PHP, where column name "10th_grade" was being type-casted to "10" failing the "bindParam" [1]. Even if they have to continue this "feature" because of backwards compatibility, the least they could have done was NOT to use it in the newer functions but no, even they have this stupid "type juggling". [1]: http://coffeecoder.net/blog/my-perfect-reason-avoid-php-type-juggling/ http://coffeecoder.net/blog/my-perfect-reason-avoid-php-type...
- Rygu 11y ago> in_array(.., .., $strict) I think you're aware of the third parameter but for anyone who reads this post, it disables the type coercion of the in_array call.
- z92 11y agoSpoiling a good rant with facts.
- pdpi 11y agoThe fact that you need to specify a third, optional parameter to get sane output out of a really basic function is still pretty rant-worthy.
- mrtbld 11y agoBut beware, with strict comparison: 1 ≠ 1.0 (because int ≠ float).
- lsaferite 11y agoBut... wouldn't you expect that? I mean, they AREN'T the same value really.
- billpg 11y ago(Shameless plug) http://blog.hackensplat.com/2012/04/php-some-strings-are-more-equal-than.html http://blog.hackensplat.com/2012/04/php-some-strings-are-mor... At which point in this article do I start making stuff up about PHP's comparison operators?
- SSLy 11y ago> If you want to compare two strings that are the same except they each use different ways of expressing an 'é', you need to add another equal sign and use ==== to differentiate them, as === will see them as equal.
- jonthepirate 11y agophp > var_dump("hello" == 0); bool(true) php >
- SixSigma 11y agousual story == is not the same as ===
- aikah 11y agonot the usual story , == should be deprecated and a warning should be displayed. PHP has explicit coercion features, devs should use them alongside with === .
- SixSigma 11y agoI mean its the usual story when people post stuff about PHP comparisons. http://php.net/md5 http://php.net/md5 the example itself uses === although no advice why is given
- ivanhoe 11y agoThere is also a weird casting when a string starts with a digit: var_dump(10 == '10xyz');
- ccannon 11y agoYes md5 is broken. We've known this for quite some time.
- mike-cardwell 11y agoThe problem is with PHP, not MD5
- untitaker_ 11y agoThis has nothing to do with md5 itself.
- mykhal 11y agoit's not _that_ broken
- drvortex 11y agoSo this is a PHP fail. But all the same, MD5 has been shown to fail collision resistance several times now.
- deleted 11y ago[deleted]
- masklinn 11y agoThe problem is this is an issue with any comparison of hex digit strings. It's a possible issue with any hash function not just MD5.
- ivanhoe 11y agoAll of this I can understand, but why then octal numbers are not compared the same way is beyond me? var_dump(0xA == '0xA'); // bool(true) var_dump(012 == '012'); // bool(false)
- seanp2k2 11y agoCheck out which types those examples get cast to and it should make more sense :) I don't know the exact rules for type detection in PHP, but it looks like that's the cause.
- vog 11y agoAs a rough generalization, all PHP code that involves "==" and "!=" should be considered broken. PHP introduced "===" and "!==" a long time ago, and every programmer should know that they have to use that, without any excuses. Also, don't use "in_array($a, $b)", but use "in_array($a, $b, true)" instead.
- imakesnowflakes 11y ago>without any excuses... Oh yea? How about this, http://www.reddit.com/r/PHP/comments/2zhg6z/how_true_is_this_php_bashing/cpjhx04 http://www.reddit.com/r/PHP/comments/2zhg6z/how_true_is_this...
- vog 11y agoI don't see how "==" would help in that situation, other than "solving" this particular issue by opening another can of worms. You simply can't use php arrays for user-generated keys in a safe manner. At least you have to add some prefix like '_stuff_' to all keys, to avoid accidental conversions. And yes, this "proper" solution (Can you ever can say "proper" in php? Anyway ...) doesn't have to involve "==", but works perfectly (and preferably) with "===".
- josteink 11y agoSo what you're basically saying is that the "standard" variations and APIs which people will find and use are broken, and the ones actually working are hidden somewhere in the documentation. And you're saying you think this is just fine? In that case, I have a hammer to sell you, and I think you know which one. http://blog.codinghorror.com/the-php-singularity/ http://blog.codinghorror.com/the-php-singularity/
- vog 11y ago> And you're saying you think this is just fine? Not sure where you read this. I didn't provide any judgement of the situation. Strawman arguments like this should have no place on HN.
- jamesmcq24 11y agosigh.. yes, == can be weird. get over it. any php dev worth anything knows to use ===
- the8472 11y agohttp://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/#operators http://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/#o...
- Killswitch 11y agohttp://forums.devshed.com/php-development-5/php-fractal-bad-design-hardly-929746.html http://forums.devshed.com/php-development-5/php-fractal-bad-...
- tellor 11y agoThis is well-known PHP-trick. Use === to right result. php > var_dump(md5('240610708') == md5('QNKCDZO')); bool(true) php > var_dump(md5('240610708'), md5('QNKCDZO')); string(32) "0e462097431906509019562988736854" string(32) "0e830400451993494058024219903391" php > var_dump(md5('240610708') === md5('QNKCDZO')); bool(false) php > var_dump("0e462097431906509019562988736854" == "0e830400451993494058024219903391"); bool(true) php > var_dump("0e462097431906509019562988736854" === "0e830400451993494058024219903391"); bool(false) php > var_dump(md5('240610708') === md5('QNKCDZO')); bool(false) php > var_dump(md5('240610708') == md5('QNKCDZO')); bool(true) php > var_dump(md5('240610708') === md5('QNKCDZO')); bool(false)
- steego 11y ago> This is well-known PHP-trick. Use === to right result. Everybody knows PHP is a trickly-typed language. Read the docs people or PHP will take advantage of your gullible ass.
- beched 11y agoHere's a threaded app for finding such collisions: https://github.com/beched/php_hash_collision_finder https://github.com/beched/php_hash_collision_finder
- ejcx 11y agoOne thing to note. The md5 and sha1 interfaces have a second param which prevents this bug. Instead of returning a string it will return binary data which won't get coerced to a float. For example: <?php if (md5('240610708', true) == md5('QNKCDZO', true)){ printf("Will never go here\n"); } PHP has a lot of.....PHPisms.
- mrclay 11y agoThere's no "binary data" type. Raw hash output can certainly start with bytes matching "0e" or "0E", it's just a lot more rare.
- hit8run 11y agoWhile I do believe that it is possible to write great Apps with PHP I tend to stay away from it because it is not statically typed. For quick and dirty proof of concept it is nice though (IMHO).
- lumpysnake 11y agoITT: PHP hate circlejerk
- erik14th 11y agoI agree that all languages have it's warts and a good programmer should know about them. I think what makes both PHP and Javascript not so great is the fact that it is so easy to overlook deadly mistakes like using "==" instead of "===" or forgetting to add a "var". And worst of all those errors can go unnoticed until something breaks and when it does it's pretty hard to find out the root of the problem.
- devy 11y agoThe fact that PHP is a dynamic language and that "==" would automatically convert the types of both ends to a flat because of the "0e" prefix of the string is problematic. Perhaps it's a bug in the PHP source code. See below. # the examples were essentially similar like this comparison. php > var_dump("0e462097431906509019562988736854" == "0e830400451993494058024219903391"); bool(true) # md5() does return a string type, but just happens to start with "0e" php > var_dump(md5('240610708')); string(32) "0e462097431906509019562988736854" php > var_dump(md5('QNKCDZO')); string(32) "0e830400451993494058024219903391" # and if PHP treats them as floats instead of strings, they all evaluated to the same thing. float(0) php > var_dump(0e462097431906509019562988736854); float(0) php > var_dump(0e830400451993494058024219903391); float(0) php > var_dump(0e087386482136013740957780965295); float(0)
- Devid2014 11y agoThis is why Strong Typing is so important !
- David_5-1 11y agoPHP : 1 week is not always 7 days: $_1week = new DateInterval("P1W"); $_7days = new DateInterval("P7D"); var_dump($_1week == $_7days); // true var_dump($_1week); var_dump($_1week == $_7days); // false var_dump($_7days); var_dump($_1week == $_7days); // true http://3v4l.org/CcAk8 http://3v4l.org/CcAk8 Same result with '$_1week = new DateInterval("P7D");' :-)
- anh79 11y agoHow about ==== and ===== and ======? For security reason, I suggest PHP to implement such operators... :D Example: "abc" === 'abc'; # ==> true "abc" ==== 'abc'; # ==> false, single-quote vs double-quote "abc" ===== 'abc'; # ==> true, this is how it works j.k :D
- shreyasonline 11y agoanother annoying thing about PHP is that it keeps emitting warning related INFO messages on webpage for visitors to see even after having proper try{}catch{} error handling. Then you got use set_error_handler for it to suppress unwanted messages
- mykhal 11y agoslightly off topic: $a = "DjBlYVWap4fQC8b3C73+NATPA2We"."c"."E+FNMAP+2WcTIdAzJQv6y2hFaP0F"."V"."y7hgdJc4ZlbX0fNKQgWdePWo3R7w"; $b = "DjBlYVWap4fQC8b3C73+NATPA2We"."d"."E+FNMAP+2WcTIdAzJQv6y2hFaP0F"."d"."y7hgdJc4ZlbX0fNKQgWdePWo3R7w"; var_dump($a === $b); // false var_dump(md5(base64_decode($a)) === md5(base64_decode($b))); // true :-P
- nerdy 11y agoNothing magic here. Be careful with the == comparison operator and its type juggling. If you want to match things precisely, use the === operator. Loose comparisons can have dangerous side-effects! The MD5 examples are really just cloaked comparisons like this one, later in the list: var_dump('0010e2' == '1e3'); ((10 x 10^2) == (1 * 10^3)) http://php.net/manual/en/language.operators.comparison.php http://php.net/manual/en/language.operators.comparison.php http://php.net/manual/en/types.comparisons.php http://php.net/manual/en/types.comparisons.php