Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Things You Don’t Know About User IDs That Will Destroy You (timetobleed.com)
69 points by ice799 on April 13, 2009 | hide | past | favorite | 16 comments


This blog post shows an interesting difference between the Perl community and the Ruby community. The Ruby community lives to write long blog posts about why you are writing code wrong. The Perl community just makes a library everyone can use to avoid getting things wrong in the first place.

(http://search.cpan.org/~tlbdk/Privileges-Drop-1.00/lib/Privi...)


Interesting point, but I think of it as teaching a man how to fish and giving him fish. If you read and understand this blog post,

1. You can write your own lib

2. You can spot bugs in other programs regarding privileges

3. You have an understanding of how privileges work and can transfer that knowledge to other programming languages/problems.

4. When you use a third party lib for, say dropping privileges, you can actually verify that they are doing it right because you actually understand what is going on and what is needed.


Consider the case where the blog post is not entirely correct. How do you tell everyone that cut-n-pasted the code from the blog to fix their apps?

You can't. At least with libraries, someone can report a bug or send a patch, and you can release a fixed version. Any reasonably competent developer will eventually notice the new version and upgrade the module. Problem fixed.

With a blog post, there is no reasonable way to push out new features, patches, bug fixes, security fixes, etc.


You are thinking in terms of code. I'm thinking in terms of knowledge.

What you should take away from the blog post is not the code. It is the knowledge. It has given a good starting point, on doing your own research. Just using a lib usually never leads to that.


Using a lib can get things done. Sometimes you have to get things done now and have to come back to understanding the problem in depth later.

Debugging through someone else's library is often a great way to do that. (Provided your language/environment's debugging support is good enough.)


Sometimes you have to get things done now and have to come back to understanding the problem in depth later.

This is a great way to create whole new problems.


Do you know every implementation detail of the database management system you use?

The fact that proprietary databases exist means that you can use libraries without understanding all the code in them.


You left out:

5. When the Ruby library for doing this is written and published, and you're trying to convince people to use it instead of rolling their own, you can refer them to this blog post.


Are you suggesting that the Perl community didn't follow the strategy of

a) making this mistake over and over for a decade

b) finally realizing, in the course of some blog posts or their equivalent, that they needed a library to fix it?

c) making that library?

Because here's what appears to be the Perl equivalent of this Ruby blog post, from 2005:

http://use.perl.org/comments.pl?cid=45240&sid=29890

This post is promoting the Proc::UID library, which was apparently only a year old at the time and was not quite finished. The release on CPAN was marked "for testing and review purposes only. Please do not use in production code."

http://search.cpan.org/~pjf/Proc-UID-0.04/UID.pm

The newer Privileges::Drop library, which you link to, dates back only to 2007.

Perl is more mature than Ruby. But perhaps only a few years more mature.


Yes, the author of Proc::UID discussed his module in public. That's not what I'm talking about here, I'm talking about the Ruby community's general love for cut-n-paste instead of actual library writing.

Anyway, compare planet perl and planet ruby some time. The Ruby posts are overwhelmingly "cut-n-paste this code" and the Perl posts are generally "here is a module I wrote". Different cultures.


Anecdotally, most Ruby blog posts I've seen describing how people are "doing it wrong" are just introductions to a gem or plugin on someone's Github account.

Seems to me that you're just taking a cheap shot at Rubyists. :)



The Smalltalk community did it like this:

    - Usenet posts about how to write code correctly 
      (predated blogs)
    - Smalltalk images that contained badly factored code
      written by junior people, in all the places where
      other junior people would look and imitate
    - Years after the heyday of Smalltalk, there's now an
      automated tool that will find bugs and critique code
      for you, but at this point there are very few who 
      care.


Another way to look at this: if you're typing "setreuid" into your code, you're doing it wrong. Most networked Ruby programs don't need to run with superuser creds in the first place. Factor the need out of your code.

The threat model in this post is a bit dated, too. The EUID is insecure if (paraphrase) "you can execute arbitrary code in the process, because you could just execute setuid()". That's true, but it neglects the fact that if I can run arbitrary code in your process, you're fucked anyways:

* Localhost nobody->root is a speed bump on most Linux deployments.

* If your app works as "nobody", so does an attacker with "nobody" creds.

* "Nobody" has network access, can talk directly to your database, and to every insecure box in your data center.


Is the complexity of the *nix IDs completely warranted or can it be mostly attributed to historical precedents? Would there be a way to significantly simplify it without really reducing flexibility (I'm not necessarily looking for a backwards-compatible way)?


The problem is not so much of user IDs, but rather how UNIX implements security. "root" can do privileged things, everyone else can't. For example, only the root user can listen on port 80. These rules are hard-coded in the depths of the OS, meaning you have to work around them.

The problem is that you don't want your process-that-listens-on-port-80 to have all the other permissions that "root" does. So you have to drop your privileges after binding port 80, resulting in the complexity of effective and real UIDs (and GIDs).

The solution is fine-grained access control. You don't want to say "run this app as nobody", you want to say "let this app connect to the MySQL server, write to /tmp/my-app, and load shared library foo". Could you implement a system like this? Yes. (SELinux is a start.)

But really, it is time for UNIX to die. "Worse is better" is getting old, and UNIX can't be fixed. Someone needs to implement a real OS (and provide UNIX compatibility so users can easily migrate).




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

Search: