8 ms·
No-SQL injection in Mongo PHP
- RyanMcGreal 16y ago> which PHP will magically turn into an associative array I think I found the issue.
- jameskilton 16y agoRails does the same thing and it's insanely useful, you just need to know what you're doing and ensuring you're protecting against this.
- emil0r 16y agoWhich means a) You're going to forget it at least once. b) For every developer mindful of this, there will be hundreds not knowing about it. If you ever put "you just need" into a sentence about security you've already lost.
- boundlessdreamz 16y agoThe default Rails way of using Activerecord will automatically sainitize inputs for you. Not turning it into an associative array doesn't add anything to security. User input need to be sanitized always. Rails make it easy and is the default way.
- emil0r 16y agoAll true. I was thinking of the submitted link still. Manually sanitizing instead of having something doing that for you is a bad idea because you will forget.
- rapind 16y agoThere's nothing stopping you from passing unsanitized params to the database. I.e. where("name LIKE '%#{params[:name]}%'") instead of where("name like ?", "%#{params[:name]}%"). While the 2nd option is definitely the recommended way to do it, there's nothing stopping you from doing it the wrong way, and I bet many do.
- RyanMcGreal 16y agoThe thing is, it's easier to do it the right way. It requires a special, deliberate effort to do it wrong. That seems like a reasonable implementation of a "magic" feature. PHP, as usual, gets it exactly backwards. It's easier to do it wrong, and requires a special, deliberate effort to do it the secure way.
- rapind 16y agoYeah maybe. Depends on the person I think. I actually find it easier to assemble a SQL string myself. If you're new to rails / AR and you're not familiar with SQL then you'll look up and figure out how to assemble the SQL via the ORM methods. If you're new to rails but an old hand at SQL, just building the string is super easy and takes you 2 seconds without looking up any documentation. Of course assembling the string AND sanitizing it requires a heck of a lot more effort. Regardless, it's not a knock on rails. Just saying it's not necessarily a magic bullet to secure apps (and I don't believe rails nor PHP needs to be).
- taylorbuley 16y agoThe "hundreds not knowing about it" was was sparked me to submit this to HN. This is important stuff and probably should not be relegated to a php.net footnote. Edit: It's not actually a footnote -- it's actually just the only item on the lonesome "Security" page.
- jasonlotito 16y agoTo be fair, it's the Mongo Security page, not the general security page, which can be found here: http://www.php.net/manual/en/security.php http://www.php.net/manual/en/security.php
- wvenable 16y agoThe web is full of these kinds of issues -- you need to escape, filter, etc, etc, every piece of user data. You either do it yourself or use some kind of abstraction layer (template engine, ORM, etc) to do it for you.
- tptacek 16y agoPut differently: "we're all doomed". Squares with our professional experience.
- rickmb 16y ago> a) You're going to forget it at least once. Which is why you should never process raw input in multiple places in your app. One method I've used for over a decade of webdev in any language: there's only one place to get the input from, and that place requires you specify what input is allowed.
- RyanMcGreal 16y agoAny security practice that addresses an insecure default state by starting with "you should never..." is doomed.
- SpikeGronim 16y agoIt is a tradeoff between ease of use and security. These sorts of features require the developer to check every single query string consumer or you end up with gaping security holes. That will result in security exploits in any moderately large codebase with multiple developers, it's just a matter of time. I would much prefer to sanitize everything always and force the app developer to spend the 1 line of code to parse into an array when they want that feature.
- drdaeman 16y agoTornado always uses lists, even when there's a single parameter. I.e. `?spam=ham&spam=ham&eggs=eggs` results in `{"spam": ["ham", "ham"], "eggs": ["eggs"]}`. While this may be not as easy to use as simple strings, it is consistent.
- ronnoch 16y agoSomehow I managed to use PHP for 8 years and never notice this... Time to double check all my input sanitizing code, I guess.
- jasonlotito 16y ago8 years and you didn't know this? I assume it's the part where it turns [] passed vars into arrays. Even still, this is only a problem is you are blindly passing around user input without any verification. The same thing is just as easily accomplished in numerous other languages. Honestly, I'm trying to figure out how someone could sanitize their input and still be affected by this.
- ronnoch 16y ago> Honestly, I'm trying to figure out how someone could sanitize their input and still be affected by this. I don't think you could, unless you tried to write your own sanitizing functions from scratch and somehow screwed it up. In PHP, htmlspecialchars(), mysql_real_escape_string() and addslashes() all do fine sanitizing array input -- either throwing an exception or returning the string "Array".
- Getahobby 16y agoHmm. I think these functions escape output, not sanitize input.
- joelhaasnoot 16y agoThe issue is trusting input you're receiving from users or the wild world out there. User data always needs to be sanitized in some way shape or form. Assume very little on the web. Think of every language as a strictly typed, pure functional programming language, where I/O is the big bad world out there and evil and blocking and complicated. Likewise, on the web you should treat any inputs as being evil... (ok, so the comparison is far from perfect, but the idea holds true)
- tptacek 16y ago"Always validate your inputs" is unfortunately one of the least useful bits of security advice given to developers; it is only epsilon away from "never make mistakes".
- sausagefeet 16y agoI agree with you, but also pointing out a strength of a language that supports phantom types helps this issue quite a bit. You can design your DB API to not allow unquoted queries.
- KaeseEs 16y agoI think you've conflated "not trusting" user data with sanitizing it. To use an analogy from SQL, using prepared statements/parameterized queries doesn't sanitize user data, but it also doesn't trust it (as it doesn't treat data as code). More generally, blacklist sanitizing is a losing game from the outset, whitelist sanitizing is hard, your best bet is to not treat data as code to begin with.
- s00pcan 16y agoI might be missing something here, having never used MongoDB, but what does this have to do with it? How else can this attack vector be used?
- methodin 16y ago$ne = not equals which translated to "give me everything not equal to foo". Using this you can basically get a dump of all the data or update with foobarred critera - updating all passwords for all users not equal to foo, for instance
- nbpoole 16y agoThere's a very good example here: http://www.idontplaydarts.com/2010/07/mongodb-is-vulnerable-to-sql-injection-in-php-at-least/ http://www.idontplaydarts.com/2010/07/mongodb-is-vulnerable-...
- tptacek 16y agoThis is not the only NoSQL-injection issue. Extra fun bonus warning: nobody knows what the quoting domains are for all the NoSQL's. Be extraordinarily careful with your keys.
- rbanffy 16y agoAny query language can be injected if you don't sanitize your input. Any object persistence layer that doesn't sanitize parameters is vulnerable to this kind of attack.
- tptacek 16y agoIf people weren't talking up NoSQL specifically as a way to avoid SQL security problems, I wouldn't have written my comment.
- rbanffy 16y agoThe problem is that under the hood there is a query language. When you have no query language, you can't inject commands into it, either by carelessly passing user input down the stack or assembling your own queries. It would be devilishly hard to inject malicious operations into ZEO/ZODB (the one "NoSQL" I am very familiar with). I can only assume it would be equally hard to do it with systems that do not try to replicate the human-friendly nature of SQL.
- tptacek 16y agoSee my original comment.
- rbanffy 16y agoMy comment has no relation to escaping. It's in fact, centered on the idea that any attempt to do so will introduce potential vulnerabilities and the only sane way out of this mess is not having a language in the first place. Anyway, the idea of blindingly assuming that just because something doesn't use SQL it's invulnerable to any kind of code injection is a very optimistic position.
- to 16y agowelcome to a 10 year old problem fixed through build-in odm like driver. raw mysql_query vs MongoCollection Obj.
- antirez 16y agoNon existing problem with Redis (not possible at protocol level), for what it is worth.
- mrkurt 16y agoIt's not exactly a protocol issue for mongo, though. If it weren't for Rails/PHP (and more) converting magical strings into objects of another type, it wouldn't be possible in Mongo either. This would be the equivalent of some helper wrapper on top of a redis driver that turned strings with a special format into, say, an MGET command that returned more than a developer meant for it to. redis is safer because it doesn't have the complex query-over-document functionality that mongo does, but it's not inherently immune.
- antirez 16y agoThe new Redis protocol (the only one used at this point) is inherently immune, with SORT we have complex queries. But the point is, the way we send every different argument to the server as a single entity with prefixed length, makes the attack impossible.
- albertzeyer 16y agoThe old Redis protocol was also not binary safe. If you are able to access the value in some `redisCommand("SET %s %s", key, value)`, you are able to inject other commands there. But the new Redis protocol is safe against that.
- mscarborough 16y agohttp://www.php.net/manual/en/book.filter.php http://www.php.net/manual/en/book.filter.php Lots of built-in options, the only reason this should be an issue is if you're not validating inputs at all, or hacking your own as ronnoch noted.
- sausagefeet 16y agoWhich is quite possible unless you have a compiler forcing you to validate. I make silly mistakes all the time in Python.
- grncdr 16y agoNot to pick on your comment specifically, but I've seen a couple of comments that imply this is the kind of mistake that one would make in a moment of absent-mindedness, and I disagree. Nobody with any semblance of a clue is writing (new) apps that access user input from PHP super globals directly. If you are ever using $_GET in your app-specific code you are doing it horribly wrong, not making a silly mistake. That being said, there are legions of clueless devs out there who will do this, and that is unfortunate.
- sausagefeet 16y agoI agree with the clueless argument, but I also think there are mountains of bugs that exist simply because one made a mistake and a dynamically typed languages can't really do much for them there.