7 ms·
One Line of Code That Compromises Your Server
- kuon 10y agoI think any sane framework should generate a random secret each time an app is generated.
- ameliaquining 10y agoNo; Django does that, and the result is that people check that random secret into source control. The correct solution is to not have the secret in code at all, but to read it at initialization time out of some kind of secrets management system (traditionally via environment variables). Unfortunately, frameworks generally can't do this in a hosting-setup-agnostic way; you have to understand the specific facilities that your PaaS or deployment system offers for this, and some (looking at you, Google App Engine Standard Environment) don't offer adequate ones.
- robertlagrant 10y agoI THOUGHT Django generated a random secret! What's MF on about?
- hansjorg 10y agoI think the purpose of that sidebar is to list the names of relevant configuration keys for some frameworks. Pretty confusing though.
- stestagg 10y agoI guess his point is that you /could/ set this to a weak key if you want, but I can't think why you ever would
- jacksingleton 10y agoah I can see how that sidebar is confusing now. the point was just to highlight the configuration names across different frameworks. as @ameliaquining points out, a randomly generated secret that's been leaked to github has much the same effect as one that is easily guessed. I'll think about ways to make it more clear! Thanks
- kuon 10y agoI am not saying the secret should be in the code itself. The app generator could generate a .gitignore including another dotfile with the secret in it. Or print a message on how important it is to configure the secret properly. My point was that a framework should not generate a working value that is insecure. And if generating no value and have the app not start without additional configuration is the best way, this should be the way to go.
- slrz 10y agoOr, for simple cases where a single server handles all clients (i.e. no load-balanced cloud setup), just generate it on startup. A server restart will invalidate sessions, but oh well.
- franciscop 10y agoGood article and callout for those projects (and mine). I am doing an express alternative[1] with something that is not secure as a temporary session secret[2] formed with `secret: 'secret-' + parseInt(1000000 * Math.random())` so I'll modify it to use a real random key from a crypto library or display a prominent warning. Then I am also documenting it in a small production security guide [3]. Also, if the key in the documentation is used there's a warning[4] similar to how Dropbox stops you from using 'correct-horse-battery-stapler' as a password. If you have any other tip/recommendation I'd be really thankful. BTW, doesn't SSL/TLS mitigate this a lot? Like, if the user is using SSL then only with physical access to a decrypted device would an attacker be able to impersonate the user, limiting greatly the possible attacks. And if someone has access to your decrypted device then you have bigger problems. Though devs who don't change 'super secret' are probably probably less likely to set up https... Edit: I almost didn't include the BTW comment because I agree that it is an important part of security, so I didn't want to make it sound less severe, but I am curious about attack possibilities with https enabled. [1] https://serverjs.io/ https://serverjs.io/ [2] https://github.com/franciscop/server/blob/master/src/config/defaults.js#L8 https://github.com/franciscop/server/blob/master/src/config/... [3] https://github.com/franciscop/server/issues/3 https://github.com/franciscop/server/issues/3 [4] https://github.com/franciscop/server/blob/master/src/config/index.js#L45 https://github.com/franciscop/server/blob/master/src/config/...
- AgentME 10y agoSSL doesn't protect you from a malicious user who is trying to crack the key used on the cookie you gave him. It just means that no one else will eavesdrop on the malicious user's connection.
- franciscop 10y agoBut then it also means the malicious user cannot eavesdrop on other users, so other users will be secure, right?
- AgentME 10y agoThe attack in the article isn't about a malicious user eavesdropping and obtaining someone else's cookie directly. It's about a user who gets a cookie from the server, brute-forces to determine the key used to sign the cookie, and then uses that key to generate cookies that authenticate them as other users (or that execute code during deserialization, etc).
- azernik 10y agoThe equivalent of leaving the default password set. Coders are not immune.
- continuational 10y agoDefault passwords are a problem with the system being configured; not with the configuration. Insecure-by-default systems should not be deployed anywhere.
- parent5446 10y agoThis is why I prefer not to pass session information to the client in the first place. Have the session key be just an opaque, cryptographically random token that is then associated with data on the server (via a keystore of some sort). Then the cookie becomes nothing more than a bearer token. There are some use cases this does not cover, such as authentication across multiple systems, where one or more may not have access to the authentication source, but even in that case it'd be preferable to have a separate, internal, private microservice that exchanges tokens for session information. None of this will stop an attacker that has network access, but that's not what the article is considering, and if somebody is inside your network you might have bigger problems than session hijacking.
- fpgaminer 10y agoThe reason is that, at scale, all the little things matter. Having to query your database for _every_ user request, to convert their session token into the server-side underlying data, gets expensive and slow. And it's a centralizing force in the architecture, requiring your session management database to be accessible by all your user facing servers. So they store the data with the client, who can pass it back to the server with every request. One less DB query. There are various rebuttals to that approach, even at scale, etc, etc. I'm certainly not advocating for it. But that's what some big applications landed on. Big apps drive most of the development of free tools, libraries, and frameworks. So it's no surprise that a lot of free tools handle this use case, even by default. In the majority of cases, the not at scale cases, of course it doesn't make sense. Most all the hot new tools don't make sense. But again, that's just an artifact of software economics. The majority of the money is made by the big apps, so most tools are built for the big apps. It's just a shame that new developers get caught up in these hip tools and base their understanding of the ecosystem on them.
- einrealist 10y agoSession key verification can be a cross cutting concern that is good enough for scale (API gateway, reverse proxy, cross cutting service). And with a verified session key, each service should be able to optimize for restoring data belonging to that session key. If the data leaves your server, it is considered potentially malicious and you have to verify and validate everything anyway. Also, with client-side stored data you lose control over the client-server state unless you validate against the server state. But then you lose all the advantages of client-side storage. Crypto cannot mitigate that.
- bshimmin 10y agoJack Singleton is a developer and security specialist at ThoughtWorks. What a splendid example of an aptronym! [0] [0] https://en.wikipedia.org/wiki/Aptronym https://en.wikipedia.org/wiki/Aptronym
- bitexploder 10y agoWhile we are at it here is another individual line that will "compromise your server". https://github.com/rack/rack/blob/master/lib/rack/session/cookie.rb#L180 https://github.com/rack/rack/blob/master/lib/rack/session/co... https://rdist.root.org/2009/05/28/timing-attack-in-google-keyczar-library/amp/ https://rdist.root.org/2009/05/28/timing-attack-in-google-ke... Of course folks are much more likely to misuse their cookie secret than purposefully break a library function. That said you can look at the history of most projects that use HMAC to authenticate data and they did it wrong. (e.g. https://github.com/rack/rack/commit/0cd7e9aa397f8ebb3b8481d67dbac8b4863a7f07 https://github.com/rack/rack/commit/0cd7e9aa397f8ebb3b8481d6...)
- cyberferret 10y agoI write most of my web apps using Sinatra (as per the article example), but do it using the Padrino [1] framework. Padrino by default sets the Sinatra session secrets to a long hash, which negates the developer from having to remember to do all this housekeeping later to tighten security on the app. [1] - https://www.padrinorb.com https://www.padrinorb.com
- arkadiyt 10y agoPadrino sets the session secret to a random value on startup if you don't set it yourself. This means that: 1) you can only run a single instance. Multiple instances will generate different secrets and not accept each others' cookies 2) restarting an instance (for instance doing a deploy) generates a new secret and invalidates all previous cookies Neither of these are desirable, and to avoid it the docs recommend [1] you set the session secret yourself via: set :session_secret, 'super secret' which gives you the exact problem the blog post is addressing, so it does not seem that Padrino does any better here. [1] - http://padrinorb.com/guides/controllers/sessions/ http://padrinorb.com/guides/controllers/sessions/
- mozumder 10y agoThe cookies spec really should be incorporated into the SSL/TLS layer. Right now it's basically performing two encryption/signing steps immediately after each other, one at the web server, and another for the applications server. This is a pain-in-the-ass for the web server framework and adds several milliseconds of redundant latency. The cookie data should be signed with the web server's private key.
- hdhzy 10y agoToken Binding achieves something simular to what you propose. See http://www.browserauth.net/token-binding http://www.browserauth.net/token-binding
- nthcolumn 10y agoI don't know why anyone would ever do this since there is no cost to SECRET_KEY = os.urandom... or even just hammering on the keyboard. It is not like you are ever going to be challenged for that password? You could even say here is another line of code that will compromise your server: rm -rf /* brb off to search github for SECRET_KEY =
- jjnoakes 10y ago> there is no cost to SECRET_KEY = os.urandom Only if you generate the key up front and use the same value everywhere. If you just call os.urandom in your app, then the cost is every restart (and every separate server instance) invalidates the cookies. Probably not what you want.
- eleumik 10y agoWhat do people here use to store password for servers ? Plain text configuration files ? I have pwd of DB in config files and found no way to put it elsewhere.
- mkarazin 10y agoPlain text can work, assuming that it is access controlled in a secure environment. Often times, during the build process, a secure secret management system or process will handle the combining of the code with configuration. For example, your developer (with no secret access) could commit code and Jenkins can fetch the configuration file from a secure and access-controlled service. Then the built code has the secrets and the developer does not. There are a lot of approaches to doing it at scale. See https://gist.github.com/maxvt/bb49a6c7243163b8120625fc8ae3f3cd https://gist.github.com/maxvt/bb49a6c7243163b8120625fc8ae3f3... for a good overview.
- eleumik 10y agoThanks ! very nice overview.
- franciscop 10y agoEnvironment variables which depending on the host are done differently. For heroku it's a setting, for a bare bones server it'd be a plain file called .env.
- tbodt 10y agoCompromise your server with this one weird line of code!
- known 10y agoI've seen one character compromising the server
- mwpmaybe 10y agoHow long would it have taken to crack the secret on that same setup if HMAC-SHA256 had been used instead? What's the recommended minimum number of bytes for an HMAC secret when using SHA1? SHA256?