Hacker News new | past | comments | ask | show | jobs | submit login
Attacking NoSQL and Node.js: Server-Side JavaScript Injection (SSJS) (mypopescu.com)
76 points by EwanToo on Dec 19, 2011 | hide | past | favorite | 35 comments



This is neat and largely spot on, but I do want to call out one specific thing that I strongly, strongly disagree with:

> Validate user input used in SSJS commands with regular expressions.

If I had a dollar for every time I saw someone trying and failing to solve things like SQL injection, XSS, and path injections with regexes, I'd be a millionaire. It's ridiculously hard to get it right. The best solution is: don't ever, ever put user input into code. Ever. Build it based on user input, but don't put user input into the code.

Edit: Just because a lot of people may not be familiar with the pitfalls, here are a couple things:

- What character set is your input string, what character set is your regex engine using, and what character set is the consumer of the input expecting? An impedance mismatch at any of these points could allow malicious strings to go right through, even if the regex would normally match it just fine. For instance, if you're emitting XML and you're using a regex to try and match bad things in that XML, consider that your regex might miss, say, UTF-16, which could be totally valid in the XML if you change the charset in the definition tag.

- You're building something that generates a file path; you want to restrict the user from moving up the directory structure and also want to make sure they're not writing into the 'foo' directory. So you do (in effect): if path =~ /\.\.\// then bail else return_file(path.replace('foo/', '')) end -- if a malicious user passes in '../../../../etc/passwd' then it'll get caught by your filter; if they pass in 'foo/bar.txt' then it'll really read 'bar.txt'; but if they pass in '.foo/./.foo/./.foo/./.foo/./etc/passwd' then it'll read '../../../../etc/passwd'. If you're modifying things after the regex, be very careful that you're not compromising the regex.


"using a regex to try and match bad things"

And that's the core failure, not the use of regexes.

Whatever you are using to filter user input, you always filter the good things in, and not the bad things out.


Exactly. For example the common case of filtering "text to be displayed via the web" is probably best expressed as a (1) a validating conversion to utf8 followed by (2) a regex that translates characters outside the safe range to XML entities.


I agree that the solution isn't to validate incoming input.

The way to avoid injection attacks is to make sure you're correctly escaping user input when you use it to compose queries - preferably using a separate abstraction layer rather than calling the escaping function manually.

The most effective tools handle escaping by default, and make you have to work hard to avoid escaping - Django escapes anything output in to a template for example, and the Django ORM handles SQL escaping for you.


I'm stereotyping and generalizing a bit, but the crowd I've seen adopting nosql and node and other "cutting edge tech" tend to be the same people who mock PHP for being crappy, invoking references to "register_globals"-style hacks as being one of many reasons why "PHP sucks!"

Is nosql going to (re)teach people that security is something you have to be vigilant of, regardless of the underlying tech? If so, good.


Simply put: The rules of web development still apply when building sites with new technologies.

The original paper is based on use of `eval`, which people using NodeJs wouldn't do (I've not seen one example of it) -especially when V8 has an efficient `JSON.parse`.

The attack against NoSQL databases is a Sql(JS?) Injection attack - and not even a sophisticated one. Sure, services like iriscouch open themselves up to this kind of attack, but the way the paper describes it is pretty much by design.


People coming from a history of pretty much just client-side programming (or moving to JS server-side from completely different languages, having worked with JS client-side) might just use eval because that is what they've done before (not knowing that JSON.parse exists). The nodejs documents don't explicitly list JSON as part of its API (because it isn't, it is part of V8's codebase) so an inexperienced programmer using the node documents as a base for tinkering might not discover the built-in JSON parser early on so use eval instead.

Admittedly you should not be using eval() client side either for much the same reasons you chould not be using it server-side, instead find a decent JSON library and use it's parse(). Modern browsers include such utility functions anyway, but you can't rely on them if you need to remain compatible with old-but-still-common junk like IE6/7/8.


"you should not be using eval() client side either for much the same reasons you should not be using it server-side"

Can you explain this? I'd think on the server side you'd do it because you should never trust client input. On the client side, though, presumably you can trust the input from your own server.

I recognize things can get a bit trickier when you have scripts from untrusted sources mingling with yours in the same page, but at that point, given the dynamic nature of JavaScript and the way behavior attached to DOM elements can be wrapped/changed, I'm not sure eval vs JSON.parse is really your biggest problem, and I could totally see someone who knew about JSON.parse going with eval on the client side using that line of reasoning.


"I recognize things can get a bit trickier when you have scripts from untrusted sources mingling with yours in the same page"

Well, that's it exactly. Today's trivial unexploitable vulnerability gets combined with tomorrow's trivial unexploitable vulnerability and viola arbitrary command execution as the web server user. Or whatever. There's no vulnerability too trivial to fix, because in reality you can never be sure that a given vulnerability is unexploitable today, or will remain unexploitable tomorrow.


Used client-side you are still exposing yourself to cross-site security issues and the like. While you are right that the client-side JS environment is prone to this by other methods, this doesn't mean you shoud open up this method too.


I'd say it's pretty widely understood [1] to not use eval() like clauses in any language simply because it's a wide open hole for security exploits.

Is this seriously not well understood? If not, then we should promote more "eval considered harmful" type screeds.

[1] https://www.google.com/search?sourceid=chrome&ie=UTF-8&#...


I've seen it used by beginners (espectially those who don't consider themselves beginners!) who are not particularly security concious yet. Books and tutorials cover it then say "but don't use it unles you really really have to becase ...": people remeber what it does but not the warnings that were attached.

I think it needs to not be covered at all for the most part in documentation that might be used by a beginner, in any language not just Javascipt, rather than telling people about it then telling them not to use it.

It gets used because it is sometimes easier than the alternatives. If people don't know about eval() until they have learned enough to be capable of understanding the alternatives and the security implications of eval() then like us they'll do their level best to never use it.


eval() is commonly understood to be among the most evil commands you can invoke when programming, and you'd better have a damn good reason for why you're using it, and why something else isn't appropriate. This is hardly esoteric knowledge.

The first rule of application programming is "don't trust user input". eval() requires that the eval'd string be trusted to avoid security holes. The two are mutually exclusive.

In the NodeJS case, this is probably a case of misinformation. If people are teaching the use of unchecked eval, then that's a pretty huge problem. I'd be very interested to see examples in the wild of this happening, though, as it seems like such an obvious mistake that most anyone trying to teach would know to avoid it.


TL;DR : Don't naively use user input (AKA validate user input)

(well.. duh! :)


Also: don't eval() user-supplied strings.


It would be nice to know whether parts of node.js itself are vulnerable to those attacks or just badly written user code


The paper is just describing common sense stuff: using eval() on user input and passing user input directly to a database.


With everything node.js provides, I can't understand why someone would use eval()... Specially with user input.


Of course they wouldn't. "Node.js" and "NoSQL" appear in the title of this article merely to get people to click the link.


A slight feeling of disappointment after reading this post (and the linked PDF). Partly because the 'attacks' listed are nothing new (we know eval() is evil), and partly because it's 2011 and people are still writing code like this.


"A slight feeling of disappointment... the 'attacks' listed are nothing new (we know eval() is evil), ... it's 2011 and people are still writing code like this."

I'm not sure I understand this line of thinking? As you say, people are still writing code like this -- why shouldn't these problems be called out?


I don't think he's disappointed that it's being called out; rather, he's disappointed that these things still happen.


Background: I've spent the last four years largely working in the information security realm, including getting a degree in Information Assurance and working as a cyber defense intern at Sandia Labs.

<strong>I hate the current state of information security.</strong> My other degree was in Computer Science and I've switched to be a full-time developer because the entire security world is full of people and posts like this one. Listen carefully: It does absolutely nothing to make demos and write posts that say you can hack things. "I use PHP" "Oh I can hack that!" Everyone can hack everything. You're missing the point entirely.

Want to help software become more secure? Dive into the software development process and give real, tangible, code writing advice helping developers learn what they should do instead of what they shouldn't do.

The advice in this article was "Don't use eval() and use something safer than JSON.parse()" Wow! Thanks! That's so helpful! How about something like: "When looking to parse JSON input, use OWASP's ESAPI function here http://code.google.com/p/owasp-esapi-js/wiki/SignedJSONSpeci...

Or how about some actual tutorials on how to correctly use nosql and sever side javascript? How about writing an open letter to MongoDB or whoever with the tutorials and lessons they should be teaching?

I'm sorry for the rant, but I've become enraged over four years of listening to security experts trying to help security with the most useless tactics. I understand a lot of them want the glory of showing how they hacked something, but if you really care about helping the world create more secure software, you need to understand what will actually help that cause. Boasting your hacking skills and telling people what to avoid does not help. Be progressive and proactive - teach people the correct way to do things!

Edit: I just thought of an analogy that might help express what I mean. Ever seen that show in the Discovery channel (I think it's cancelled now) where the two ex-robbers go help a family secure their house? First, one of the guys shows them how exposed they are by breaking in their house and stealing all of their stuff. Then, the other guy brings in security system tools and shows the family what they need to be doing in order to protect themselves. Usually the advice isn't very life changing and the family is happy that they can make little adjustments in order to be safer. The current state of information security is exactly like if they had that show without the second guy coming in and showing how they should protect themselves. There are a ton of security experts out there that just like to break stuff that get to go hack stuff and say they're helping people protect themselves when they offer virtually no advice or education on what to do.


Step back from MongoDB and Node.js and whatnot and look at simple Ruby on Rails and Django applications. Heck, pan all the way back to J2EE Java web apps.

Best practices for securing these kinds of applications are well known, well documented, supported by tutorials and libraries.

How many J2EE applications do you think we work on that survive first contact with a pentest team?

I don't know what to tell you about the tone of this particular blog post. I also find the tone of published security research to be grating, especially over long periods of time, most especially coupled with trade press coverage.

But please do not kid yourself. We are not a few actual tutorials and open letters (?) away from secure web applications on any stack, let alone the new ones where developers actually start projects assuming that "NoSQL" does in fact mean "NoSQLI".

It's best to think of presentations like this as having a very narrow thesis: "Developers widely assume technology X is free from application security flaws. In this presentation I demonstrate conclusively that this isn't the case. The contribution made by this research is the confirmation that programming mistakes that are similarly pernicious and damaging as SQL Injection do exist in this technology."


Saying that a fundamental different approach is needed to improve software security is radically different than saying we are "a few tutorials and open letters from secure web applications." My rant was the former.


I got "tutorials" and "open letters" from your comment.

I fundamentally disagree with the idea that publishing new ways to break software isn't the best tool we have to improve software security.

But even if I didn't, if you're going to berate someone for publishing an attack instead of doing something else, the onus is on you to come up with a plausible alternative.


Right on. These folks like to talk about how they can pown everything under the sun. That kind of talk is cheap and easy. On the other hand, writing an article with tangible ways to protect your MongoDB database would take some effort and would not be interesting to them.


It is not cheap and easy to find new vulnerability classes. The people who say things like this are virtually always members of the set of professionals who have never discovered any new attack classes at all.

It may be harder to build something good than it is to break things, but it is almost invariably harder to break things than it is to build the average thing.


You're right. Finding vulnerabilities is not easy. I was talking about people in the security industry that just like to talk.


Arguments like these can be used for pretty much any other technology, this is not NoSQL nor Node.js specific.


Most of these technologies provide tools to make code safe, and generally make it easier to be safe than not to be (templates escaping by default, expression languages[0] and ORMs[1] making non-escaping code longer and more complex than escaping codepaths, etc...)

That does not seem to be the case here, not in the tools, and not in the culture.

[0] http://www.sqlalchemy.org/docs/core/tutorial.html

[1] http://www.sqlalchemy.org/docs/orm/tutorial.html


Yes, but in very few cases are the server- and client-side languages the same one.


For the purposes of security, I don't think that matters.


It does help explain the temptation of jamming client JSON right into a JSON object store.


Goes back to the same thing we've known for years. You must treat all user input as toxic poison. Do any frameworks take care of this for you automatically? Because it seems like this is the root of most attacks on web apps and I'm wondering why we never seem to learn.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: