Securest way to authenticate users against /etc/shadow using PHP?

This question became important to me, since I’m setting up a Horde environment and want to use the system accounts. Doing some search I found mainly 4 ways of doing that, which all seem to have some drawbacks. Now I’m wondering, which one is most secure or if I’m missing some alternatives.

  • Method 1: Use PAM (PHP)

    Horde offers an auth plugin that makes use of the PAM library. Works fine, but the webserver needs read access to /etc/shadow. I found some statements saying this is as secure as publishing the password file for download.

  • Method 2: Use /bin/su (PHP)

    In addition, Horde provides a module that uses /bin/su to authenticate by calling fopen (file open) on /bin/su -c /bin/true $username and writing the password to this “file”. Currently, this does not work for me. AFAIK, this is probably because /bin/su is configured to only work in a terminal.
    I read it was possible to allow this usage of /bin/su, but it would be insecure.

  • Method 3: Use external program (command line)

    I could write a small program that makes use of the PAM library and is invoked by PHP. Using SUID, no one could access /etc/shadow. However, I have to pass the password as an argument to or pipe it into my program, which again is said to be a security risk. (I guess that’s the reason, why /bin/su does not allow it by default.)

  • Method 4: Use external program (local network)

    Same as method 3, but the communication could be done via unix sockets or tcp connections. I don’t know whether this is more secure than #3, probably equivalent to the question whether it’s harder to spy on local network connections than on tty!?

I think it is clear, why the first option isn’t a good idea. But I don’t know, what’s wrong with the others, so I would be glad about some short explanations.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

Method 1: I don’t like simply because in 2 seconds of thinking about it those comments are essentially correct. You’re creating a surface that exposes your /etc/shadow file, whether it’s exploitable or not, I simply don’t like that having to do that.

Method 2: is also bad. Encoding passwords in a file is just dumb. Passing them through a pipe seems equally dangerous.

Method 3: is probably the way I’d go, and I don’t think you’d have to write your own solution from scratch. In a couple of minutes of googling I found this implementation that someone put together using the libpam API.

c implementation

excerpt of C implementation – pam.c

#include <security/pam_appl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct pam_response *reply;

int null_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) {

        *resp = reply;
        return PAM_SUCCESS;

}

static struct pam_conv conv = { null_conv, NULL };

int main(int argc, char *argv[]) {

        int retval;
        char *user, *pass;   

        if(argc == 3) {

                user = argv[1];
                pass = strdup(argv[2]);

        } else { 

                fprintf(stderr, "Usage: login [username] [password]n");
                exit(1);

        }

        return authenticate("system-auth", user, pass);

}   

int authenticate(char *service, char *user, char *pass) {

        pam_handle_t *pamh = NULL;
        int retval = pam_start(service, user, &conv, &pamh);

        if (retval == PAM_SUCCESS) {

                reply = (struct pam_response *)malloc(sizeof(struct pam_response));
                reply[0].resp = pass;
                reply[0].resp_retcode = 0;

                retval = pam_authenticate(pamh, 0);

                if (retval == PAM_SUCCESS)
                        fprintf(stdout, "Authenticatedn");

                else
                        fprintf(stdout, "Not Authenticatedn");

                pam_end(pamh, PAM_SUCCESS);

                return ( retval == PAM_SUCCESS ? 0:1 );

        }

        return ( retval == PAM_SUCCESS ? 0:1 );
}

command to compile it

$ gcc -g -lpam -o chkpasswd pam.c

example run

$ ./chkpasswd myusername mypassword

I would imagine that with a little effort this approach could be adapted to suit your needs with Horde.

PHP implmentation

As another alternative to this approach you could potentially roll your own in PHP. I found this PAM library on the PECL website that looks like what you’d want.

I’d also take a look at how the Moodle project does it. It’s discussed here.

PAM from a security perspective

Looking at the purpose of PAM I would expect that the API interface was designed so that no access to lower level entities, such as the /etc/shadow, would need to be required so that users of the API can use it. This is discussed a bit on the Gentoo wiki in this article titled: PAM, section: How PAM works.

exerpt from How PAM works

So when a user wants to authenticate itself against, say, a web application, then this web application calls PAM (passing on the user id and perhaps password or challenge) and checks the PAM return to see if the user is authenticated and allowed access to the application. It is PAMs task underlyingly to see where to authenticate against (such as a central database or LDAP server).

The strength of PAM is that everyone can build PAM modules to integrate with any PAM-enabled service or application. If a company releases a new service for authentication, all it needs to do is provide a PAM module that interacts with its service, and then all software that uses PAM can work with this service immediately: no need to rebuild or enhance those software titles.

Method 4: Also a good alternative. There should be good accessibility to libraries and such to make the calls necessary to access something like LDAP over the wire to do your authentication for you. An LDAP server could also be setup on the same system as the Horde installation, configuring it for just Horde’s use.

This would gain you access to the underlying system’s authentication, potentially, by “wrapping” it in an LDAP service for Horde to consume.

References


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x