12 ms·
Clojure web security is worse than you think
- St-Clock 13y agoI believe this warning could apply to any young ecosystem or micro-framework (e.g., bottle). Could web applications written in Go, or to a lesser extent, node.js, suffer from the same shortcomings? After working so much in Django, I've been interested in smaller, leaner solutions, but then, as my feature list keeps growing, I find I miss all the bells and whistles provided by larger frameworks. I did not think of the security implication before reading this article.
- asdf1234 13y agoI've looked at a lot of Node, Sinatra, and Compojure web apps and the vast majority of them are vulnerable to a variety of attacks. CSRF protection in particular is almost never handled and when it is it's often not done properly.
- leephillips 13y agoCSRF protection is handled by Django, for example, by default - an example of something you'd be giving up if you decided that Django is too "big"; now you need to figure this out yourself and find a library that provides it or program it yourself and hope you get it right.
- phillmv 13y ago> Could web applications written in Go, or to a lesser extent, node.js, suffer from the same shortcomings? Yes, and they do. And there's no "lesser extent"; if I can't set up a fresh node app with the correct defaults for all of this stuff - if it's not safe out of the box, and I don't have to go out of my way to pick crappy settings - then it's just as vulnerable. People made a lot of fun out of the Rails vulns that hit last year but they were the visible growing pains of having to mature a framework. It's not about the individual bits, it's about the ecosystem at large.
- jerf 13y agoMy dream someday is to write a secure-by-default web framework. I've been collecting a list of things it needs to do. It's not surprising that few-to-no frameworks get it even remotely right... there's a lot more to it than meets the eye. CSRF, for instance, is hard to get right. There's a lot of "CSRF" implementations out there, where the scare quotes are part of how I'm naming them. There's headers to avoid clickjacking, which you really ought to default to the strongest protection level and make the user explicitly loosen if they need it. There's "Content Security Policy" headers that ought to be configured. And there's a pervasive problem where the security model for resource access is just laughable... it's up to you to hopefully authenticate a user correctly, and hopefully, you authorize them (hopefully, your framework realizes those are two distinct concepts! but I gotta tell you, the odds are against you), and hopefully, resources don't default to being universally available, and hopefully, that code is all correct.... there's stuff you really ought to do to the querystring to prevent enumeration attacks that would be interesting, there's the whole matter of whether your template permits, encourages, or begs you to shoot your entire site full of cross-site scripting attacks unless you laboriously explain to the template system each and every time "no, I don't want an XSS here... no, I don't want an XSS here... no, I don't want an XSS here" (even after 15+ years of experience here, I still can not reliably work in a templating system like this, something always slips through)... session management is a great deal harder than it looks... framework users should probably actually not be given access to the user's cookie in any direct form because that's begging for problems (darned near anything you can do to a cookie is insecure), to say nothing of how they ought to default to no HTTP and Secure... it's a nightmare out there.
- shadowfiend 13y agoThough we don't hit every one of your points, the Lift framework (http://liftweb.net/ http://liftweb.net/) hits a lot of them, and aims to be secure by default as much as possible. XSS is difficult by default because everything lives in a reified XML tree more or less until it goes down the pipe. SiteMap, which is the way that you do routing, disables access to anything that isn't explicitly declared in the site map. CSRF is based on randomized ids for each field and form, tied to this session, this page, and a specific callback function on the server. Content-Security-Policy isn't configured by default at the moment, though that's a good idea to add. X-Frame-Options is set by default. A bit more at http://seventhings.liftweb.net/security http://seventhings.liftweb.net/security .
- route66 13y agoI would want to turn the question around and (genuinely, not rhetorically) ask: which ecosystems right now do have a good security baseline? Am I wrong when I guess Java/.Net/Ruby and possibly more recent PHP frameworks?
- jaegerpicker 13y agoASP.NET MVC 4 and later is pretty decent, Rails is getting better but recently had a large series of problems, and django is one of the most secure by default web frameworks that I've ever used. Django really gets a lot of things (sessions, CSRF, XSS, etc..) right out of the box. Grails is pretty decent but I don't have a lot of in depth Java framework experience but it seems to vary based on the framework.
- MAGZine 13y agoSymfony on PHP has a great security baseline--though it's pretty complicated.
- deleted 13y ago[deleted]
- manishsharan 13y agoI will leave this here http://www.javalobby.org/articles/acegisecurity/part1.jsp http://www.javalobby.org/articles/acegisecurity/part1.jsp
- john2x 13y agoI felt some relief after watching the presentation. I thought I was just a whiny newbie who was spoiled by Python/AppEngine (although I guess the spoiled part is true). Turns out it is a real issue with the Clojure ecosystem. Another talk from the conference I'm glad was presented is "How Clojure Works"[1]. Towards the end, he shows the negative effects on tooling caused by Clojure's dynamic + hosted nature. Clojure's stacktraces are a nightmare. And the painful startup time kind of negates the excitement a newcomer might have towards REPL-oriented development. Hopefully it won't be too long until things improve. [1]: https://www.youtube.com/watch?v=8NUI07y1SlQ&list=PLZdCLR02grLp__wRg5OTavVj4wefg69hM https://www.youtube.com/watch?v=8NUI07y1SlQ&list=PLZdCLR02gr...
- sillysaurus3 13y agoIt's always better to have more people reviewing the security of an application, even if they seem like a whiny newbie.
- leephillips 13y ago"the painful startup time kind of negates the excitement a newcomer might have towards REPL-oriented development." But you just need to start up once and then work all day in the REPL. Unless you mean that the JVM startup means that Clojure is not a good choice for writing utility scripts and such. EDIT: As pointed out to me below, and in the excellent talk linked above, it's much more the Clojure bootstrapping time, which almost dwarfs the JVM startup time.
- omaranto 13y agoThe startup time that makes Clojure unsuitable for utility scripts and such is really Clojure's, not the JVM's! JVM start up time is actually quite small these days. See for example, http://nicholaskariniemi.github.io/2014/03/19/solving-clojure-boot-time.html http://nicholaskariniemi.github.io/2014/03/19/solving-clojur...
- stcredzero 13y agoHeh. Back in the day, Smalltalk had a reputation for being too slow to write command-line apps and utility scripts. There were even bits of wonderful tech developed that could produce Smalltalk images as small as 45k! But even more surprising: You could take the default VisualWorks, tell it to skip the herald sound and the splash screen and shut a few other things off, and it would load its 12MB default image faster than Perl 5 could start up with a 768k memory footprint.
- eudox 13y agoWeb development is very particular because of security. You can write, say, a console newsread with any programming language that has an XML parser and a curses binding. But if you want to write a web application that will actually see production, you need a web framework that has been sufficiently battle tested and audited by security-competent people. Which is a shame, because I'd really like to be able to use Common Lisp for web development. But as much as I love the language, you have to be reasonable.
- userbinator 13y ago> you need a web framework that has been sufficiently battle tested and audited by security-competent people Or alternatively, you just need to be careful with keeping things simple and straightforward. IMHO frameworks only hide problems somewhere else beneath layers of complexity. Assuming a fixed bug-rate, the more code there is, the more bugs that will be present (and whether they get discovered is another issue.)
- adestefan 13y agoThe argument is that making things too simple is what kills you. The defaults are not secure and you need to take steps to make sure you are secure. This is one area where frameworks are huge plus. Good ones ship with security conscious defaults.
- chc 13y agoThis isn't about bugs in the sense of "code that is incorrectly written for what it was meant to do." It's more about bugs in the sense of "code that was written correctly, but which does not do things it should do because you either didn't think of or didn't care about them when you were writing it." It is easier and often simpler to allow vulnerabilities than it is to prevent them.
- adestefan 13y agoYou news reader example is a poor one. There have been a ton of vulnerabilities in XML parsing libraries over the years. Of course the attack surface is different (I need to engineer an attack that makes you open my vulnerable XML stream versus bang away on your web app), but the vulnerabilities are still there and as a programmer you need to be security conscious on every platform.
- moondowner 13y agoThe title should be: Don't assume security is happening automatically under the hood. Even if using a web framework which supports security out of the box, don't take it for granted either. For example: that's a common error developers make when using Spring Security. It's powerful and full-featured, and developers get security and everything in a breeze, but when doing things on the fly misconfiguration happens and vulnerabilities are out there in the open.
- whyme 13y agoI've spent the last 3 years developing in Clojure and found I was quite happy not having an all encompassing framework. It forced me to learn all these issues and understand them well enough to be able to customize each and align them with a products design. Sure it's more work, but in my mind, it's worth it.
- phillmv 13y ago> It forced me to learn all these issues and understand them well enough to be able to customize each and align them with a products design. This is a standard developer response - I recall when Sinatra was a fresh kid on the block, and the same arguments people used against Rails - but just because something is more fun doesn't mean you're going to get all these details right. The attack surface in modern web apps can be such a large search space that the majority of people will never get it right. The point behind frameworks is that you can engage in efficiencies in scale when it comes to sensible defaults; even the most well seasoned and security paranoid developer can drown in the cornucopia of details that all have to be done right.
- whyme 13y ago> This is a standard developer response vs. a what? I've worn many hats in my day, the least of which has been a developer hat. There's equal risk in relying on a code base incorporating features with underlying concepts that you or your team does not understand. I'm all for having a framework, where you can review the code and be comfortable with what you're relying on, but in the absence of having a good one, well then build one. The benefits Clojure brings to the table more than make up for the work in either case. There's just no excuse for not knowing the concepts and not knowing if your product needs them.
- phillmv 13y ago>The benefits Clojure brings to the table more than make up for the work in either case. No one's saying "stop using clojure". The argument here is "build a clojure framework lots of people use". >There's equal risk in relying on a code base incorporating features with underlying concepts that you or your team does not understand. You do this all the time. I mean, I understand on a high level what my computer does but I can't describe to you the exact tree balancing algorithm my filesystem uses, how my CPU performs cache invalidation and branch prediction or even how exactly the JVM works. Computers are too complex to not rely on underlying concepts you or your team doesn't understand. The point is, within just the context of a web developer developing a web application there is too much stuff to know to always get it right. We need to reduce the number of things people have to think about, or else we'll always miss something.
- manishsharan 13y agoWeb Application is one of the places where Clojure's java compatibility falls short. I have a ton of time invested in Spring + ACEGI security and it just works. I have been exploring on how to develop servlets, which can use servlet session, in Clojure and they all look very ugly compared to normal Compojure based apps. I am coming to the opinion that maybe its not ready for J2EE web apps , which is a shame as J2EE has a very rich ecosystem.
- ddellacosta 13y agoThe talk he links to (https://www.youtube.com/watch?v=CBL59w7fXw4 https://www.youtube.com/watch?v=CBL59w7fXw4) is really fantastic. Kudos to Aaron Bedra for issuing a well-considered and practical wake-up call to the Clojure community. I support a Clojure/ClojureScript web app in my day-to-day work. I've also written an OAuth2 workflow for friend (https://github.com/ddellacosta/friend-oauth2 https://github.com/ddellacosta/friend-oauth2 ...pull requests welcome), one library Aaron Bedra spends a lot of time talking about. The story really is exactly how he describes--Clojure web security could be better. I suppose you could argue that, at least, the defaults are generally not bad...but that's because there aren't defaults in many cases. I think the main issue is, ironically, the same thing that makes Clojure development so great: you end up composing a bunch of small libraries together, each of which do one thing well. But as Aaron points out, there are things that aren't taken care of and you can't assume they are done for you, and a lot of security is something that you don't technically need to get a web app working... I wouldn't want to give up the approach of composing a bunch of libraries to build concise, easy-to-reason-about web apps in Clojure--I think it helps with security in and of itself--but the community could really benefit from having more libraries which nail these things down and help developers build web apps more safely, with less work. That said, I don't think it's all bad: you can build high quality, secure web apps in Clojure, it just requires you to really pay attention to security. And we should be doing that anyways, right?
- route66 13y agoAnother important thing he points at is to not write you own incarnation of every library you find lacking but provide patches/support/whatever to existing ones. While it might help your CV to have just another template library (which will inevitably be lacking again) on github, the ecosystem profits more from a few well defined and long-term maintained choices.
- stcredzero 13y ago"Yet Another Unmaintained Library" is the new useless CS master's thesis.
- freshhawk 13y ago
- homakov 13y agoAll non-mainstreem web frameworks are very immature in terms of web security. No CSRF/XSS/SQLi projections built in, don't even say about security headers. If you use an unpopular framework you should do all protections yourself.
- mercurial 13y agoAFAIK, the Flask-WTF extension for Flask does CSFRF for forms. Flask also protects from XSS per default.
- mantrax3 13y agoSQL injection is not a problem of web frameworks, because SQL should never be a part of the web layer of an application in the first place.
- collyw 13y agoIt shouldn't be but that's not always possible.
- mantrax3 13y agoIt is always possible. Name one case where it isn't, and I'll tell you how it's possible :) Web frameworks should handle input (routing, request fields, url query) and output (templates). That's it.
- collyw 13y agoOK, Django ORM, conditional aggregates - these were not possible last time I checked. You can do it at the application level, but say you want to keep the performance up, you need to drop into SQL.
- joevandyk 13y agoVirtually all web frameworks encourage SQL. So it is a problem. Making a private api to access the database can add a lot of needless complexity.
- pc86 13y agoFTA: > and session cookies don't default to http-only flags (allowing XSS attacks to steal them). Can someone explain that to me?
- cryptolect 13y agoTake a look here: https://www.owasp.org/index.php/HttpOnly https://www.owasp.org/index.php/HttpOnly
- dminor 13y agoSetting this flag on a cookie means it can't be accessed from JavaScript, so a malicious script won't be able to determine your session (for instance).
- jmnicolas 13y agoSo what are the secure by default web frameworks apart Django and Rails ?
- gclaramunt 13y agoScala Lift
- mantrax3 13y agoNothing is secure by default, even Django and Rails. You can always shoot yourself in the foot, if you don't know the basics about security. This is why the solution isn't relying on your framework, but on your competence.
- e12e 13y agoFor something fairly modern, you might want to have a look at web2py. It goes to quite great lengths to balance sane-out-of-the-box and developer productivity: http://www.web2py.com/ http://www.web2py.com/
- mantrax3 13y agoMany things said in that video are kinda off. He mixes password hashes and MAC (message authentication codes), saying we should HMAC our password hashes. There's little to gain from that: - Password hashes exist to hide passwords. The attack is to discover the original password by brute force, dictionary, rainbow tables etc. The protection against this is irreducibly slow hash algorithms and unique public salt per hash. - MAC exists to authenticate message origin. Unlike passwords, the message is often public. The attack is therefore not to discover the message, but to manipulate the message, yet make it appear from the same origin as the original message. The protection against this is the HMAC algorithm with a secret key that only the original message author has. HMAC-ing your password hash won't stop, or even significantly slow down any of the attacks performed against password hashes, so it feels cargo cultish to claim it's just magically more secure by using it. It's even more WTF-y to claim a password hash library should offer HMAC, or it's insecure. Once a system is compromised, and the attacker doesn't care to recover the original password, it's far more trivial to just replace the hash or just directly read the data protected by the login directly in the DB, rather than play out a MAC attack on a pass hash. It makes no sense. HTML escaping. You either escape for HTML or you don't. There's no sane way to escape some of it. His idea that we should be able to escape some tags, but skip (or "strip") others is a huge vector of attack as HTML is notoriously filled with edge cases that your selective escaping/stripping engine won't have. It's not trivial to parse what's a tag and what isn't a tag to a browser, trust me. It only looks trivial if you're ignorant. If you want to allow some tags, and disable others (say, allow bold/italic on forums, but nothing else) you should go through a strict DSL allowing only those types of formatting, which are then converted to HTML. Just like HackerNews does it - I type star-word-star and I get "word" in italic. That's a DSL. That DSL could be made to look like HTML, but it won't be HTML. It's fully parsed and rebuilt from the DSL syntax tree. So it can be made safe. Selective HTML escaping without those crucial steps is almost impossible to make safe by comparison. His rant about "there are too many templating engines - we should stop" - yeah, good luck saying we should stop and this working out. Likewise about databases. "Let's just stop". B.S. The thing he's missing is that different DB engines have different strengths and weaknesses. That's one major reason there are so many, and why many get used in the same project. PgSQL isn't SQLite isn't MongoDB isn't Redis. By enforcing one type of database for multiple separate project components, you don't improve security, you just cripple architecture and performance.
- borski 13y agoThis presentation echoes a lot of what we've seen. For what it's worth, we scan a lot of Clojure apps and find a lot of the types of vulnerabilities Aaron/John are talking about. Feel free to run a free scan at https://www.tinfoilsecurity.com https://www.tinfoilsecurity.com if you want to try it out. :) Would love feedback.
- danneu 13y agoWhen I think of other developers like me that are building projects solo on top of Express/Sinatra/Compojure, the most helpful resource would be a simple checklist. For example, the CSRF section could briefly explain what cross-site request forgery is, `<img src="http://example.com/logout">` http://example.com/logout">`, and recommend some approaches and good practices. Code examples could be provided for various languages/frameworks each in its own tab. The Clojure tab could demonstrate https://github.com/weavejester/ring-anti-forgery https://github.com/weavejester/ring-anti-forgery and a `anti-forgery-form-to` macro that wraps `hiccup.form/form-to` and inserts `(ring.util.anti-forgery/anti-forgery-field)` into the form. The XSS section could remind us to ensure that our templates are escaping user input. The Clojure tab could chart the safe vs unsafe templating libs. (Hiccup is unsafe) The Sessions section could remind us to sign our cookies so that someone can't just change a cookie from {:user-id 42} to {:user-id 1}. And that our never-expiring authentication cookie means that anyone with that cookie can log in as that user forever. It could explain an overview of the main solutions and their drawbacks like how to back sessions by a database or set an expiration within the signed cookie. Just like convos about crypto, discussions about security too frequently turn into some abstinence-only pamphlet.
- stcredzero 13y agoJust like convos about crypto, discussions about security too frequently turn into some abstinence-only pamphlet. As opposed to a "Purity Test" as a checklist?
- deleted 13y ago[deleted]
- stcredzero 13y agoPerhaps a better title would be "Complete beginner web apps in Clojure less secure than complete beginner web apps in other environments." (EDIT: Isn't security a perfect example of a place where (good tech + good community) > (miracle tech + bad community)?) This brings to mind an incident, about which I'll say: While I do find that the community is friendly and a source of satisfying discussion in person, the Clojure community online is notably less beginner friendly than other language communities. (tl;dr - Attempts to "help" newbs that are really opportunities to be a language weenie considered harmful.) I find some parallels with the Smalltalk community, which had a reputation for an "ivory tower" attitude and a "Not Invented Here" snobbishness. When I was a beginner in Smalltalk, a coworker of mine had written a nice but arbitrary little DSL specification language using Array literals and symbols. So I made some sort of comment about the syntax she'd created, and which prompted a knee-jerk reaction about how Smalltalk had a small non-ALGOL syntax -- as if I were totally unfamiliar with Smalltalk syntax. I've had experiences like this asking about the arbitrary function definition-like syntax of Compojure web application routes. Those look somewhat like function definitions, but they're really macros. I had tried for some time to Google the answer, but no one had ever posted about the exact code to do what I wanted. (Which wasn't at all abstruse. Something like getting access to the entire request map while modifying the returned session.) Well, it turned out that all I needed to know was to not refer to the request as [request] but as: request But instead, I got people hounding me on IRC, saying "It's all made out of functions" - with what struck me as an almost cult-like zeal - https://www.youtube.com/watch?v=ZYTkSFRmKzM#t=5 https://www.youtube.com/watch?v=ZYTkSFRmKzM#t=5 One individual snidely comments he'd put me on "ignore" and others kept telling me to go read the source code, and how wonderful that it was all made out of functions, and how wonderful it would be once I finally understood. Well, I told them that I did understand that, and that "everything being functions" had little direct bearing on what I was asking about. I am reminded of how Smalltalkers got a chip on their shoulder from the circumstance of Smalltalk's significant differences from mainstream. (Me included, I am afraid.) Just what kind of community treats with newcomers by assuming that the newcomers are lying and then telling them to go read Lisp macros? Also, this is only the most easily related situation I've encountered while interacting with the Clojure community. There have been others. No non-algol patterned language has ever gained more than a niche acceptance. If Clojure doesn't want to commit long term mindshare suicide, some attention needs to be paid to avoiding inadvertent hostility to newcomers. (This includes unintentionally being a bad security-defaults minefield.) Smalltalkers had the same "read the source" knee-jerk. In the end, it didn't work out so well. Care needs to be taken to understand exactly what the newbs are asking, because they know the least about how to formulate the question. Also, if you find yourself running a simplistic "pattern match" head-daemon eagerly looking for opportunities to bedazzle the newb with your wonderful, superior, and different way of doing things, just stop. You are giving your community a "weenie" reputation and your mental energies are better used elsewhere.