librelist archives

« back to archive

how to dropping privileges for different requests?

how to dropping privileges for different requests?

From:
Artem Chekunov
Date:
2014-11-13 @ 09:56
Hi folks,

i have a little question
i have flask app and i want use in uwsgi
i need to upload files into home directory of different users
and i want dropping privileges from the root to a target user before

i want to use something like this:
<code>
@app.before_request
def before_request():
    if os.getuid() == 0:
        os.fork()
        os.setuid(get_user_id(<TOKEN>))

@app.teardown_request
def teardown_request(exception):
    if os.getuid() != 0:
        os._exit(0)
</code>

but it's not work

any ideas?

Re: [flask] how to dropping privileges for different requests?

From:
Charles
Date:
2014-11-13 @ 10:29
On Thu, Nov 13, 2014 at 4:56 PM, Artem Chekunov
<scorp.dev.null@gmail.com> wrote:
> Hi folks,
>
> i have a little question
> i have flask app and i want use in uwsgi
> i need to upload files into home directory of different users
> and i want dropping privileges from the root to a target user before
>
> i want to use something like this:
> <code>
> @app.before_request
> def before_request():
>     if os.getuid() == 0:
>         os.fork()
>         os.setuid(get_user_id(<TOKEN>))
>
> @app.teardown_request
> def teardown_request(exception):
>     if os.getuid() != 0:
>         os._exit(0)
> </code>
>
> but it's not work
>
> any ideas?

Why not just chown the uploaded files after saving it?

Re: [flask] how to dropping privileges for different requests?

From:
Artem Chekunov
Date:
2014-11-13 @ 12:03
because if one of some requests will crushed, file in user home directory
will have owner root

anyway main goal is each request should handled within user context



>
> Why not just chown the uploaded files after saving it?
>

Re: [flask] how to dropping privileges for different requests?

From:
Lars Hansson
Date:
2014-11-17 @ 06:23
This is not possible because you can't go back to root once you've
dropped the privs.

On Thu, Nov 13, 2014 at 8:03 PM, Artem Chekunov
<scorp.dev.null@gmail.com> wrote:
>
> because if one of some requests will crushed, file in user home directory
> will have owner root
>
> anyway main goal is each request should handled within user context
>
>
>>
>>
>> Why not just chown the uploaded files after saving it?
>
>
>
>

Re: [flask] how to dropping privileges for different requests?

From:
Charles
Date:
2014-11-17 @ 07:01
On Thu, Nov 13, 2014 at 7:03 PM, Artem Chekunov
<scorp.dev.null@gmail.com> wrote:
>
> because if one of some requests will crushed, file in user home directory
> will have owner root
>
> anyway main goal is each request should handled within user context

Another idea: run 'sudo su <username> mv /tmp/uploaded_file
/home/username/target'

You can set the sudo policy so that it does not require asking for password.

Re: [flask] how to dropping privileges for different requests?

From:
Matthias Urlichs
Date:
2014-11-17 @ 07:52
Hi,

Charles:
> Another idea: run 'sudo su <username> mv /tmp/uploaded_file
> /home/username/target'
> 
No, you run "sudo -u <username> <whatever>" and specifically allow your web
user to run "whatever" on any user.

Also, "whatever" should be a script which checks that (a) the UID is of an
ordinary user, (b) the destination doesn't exist and (c) is within the
user's $HOME, (d) the source belongs to the web user, is not a symlink,
is in your temporary upload directory and not e.g. /etc/shadow, (e) you
have been called by the web user and not Joe Script Kiddie, (f) …
Directly using /bin/mv is not adequate; if you do that you might as well
run the whole web server as root.

Also², "su" is completely superfluous here.
It doesn't even work the way you think it does:

# strace -f -eexecve su root /bin/cat /dev/null
execve("/bin/su", ["su", "root", "/bin/cat", "/dev/null"], [/* 25 vars */]) = 0
Process 32032 attached
[pid 32032] execve("/bin/bash", ["bash", "/bin/cat", "/dev/null"], [/* 29 
vars */]) = 0
/bin/cat: /bin/cat: cannot execute binary file
#

/bin/su is a stone-age program and should not be used for *anything* IMHO.

> You can set the sudo policy so that it does not require asking for password.

If you really allow anybody to run /bin/su in /etc/sudoers, then sorry but
you deserve to get rooted. :-/

-- 
-- Matthias Urlichs

Re: [flask] how to dropping privileges for different requests?

From:
Charles
Date:
2014-11-17 @ 08:14
On Mon, Nov 17, 2014 at 2:52 PM, Matthias Urlichs <matthias@urlichs.de> wrote:
> Hi,
>
> Charles:
>> Another idea: run 'sudo su <username> mv /tmp/uploaded_file
>> /home/username/target'
>>
> No, you run "sudo -u <username> <whatever>" and specifically allow your web
> user to run "whatever" on any user.
>
> Also, "whatever" should be a script which checks that (a) the UID is of an
> ordinary user, (b) the destination doesn't exist and (c) is within the
> user's $HOME, (d) the source belongs to the web user, is not a symlink,
> is in your temporary upload directory and not e.g. /etc/shadow, (e) you
> have been called by the web user and not Joe Script Kiddie, (f) …
> Directly using /bin/mv is not adequate; if you do that you might as well
> run the whole web server as root.
>
> Also², "su" is completely superfluous here.
> It doesn't even work the way you think it does:
>
> # strace -f -eexecve su root /bin/cat /dev/null
> execve("/bin/su", ["su", "root", "/bin/cat", "/dev/null"], [/* 25 vars */]) = 0
> Process 32032 attached
> [pid 32032] execve("/bin/bash", ["bash", "/bin/cat", "/dev/null"], [/* 
29 vars */]) = 0
> /bin/cat: /bin/cat: cannot execute binary file
> #
>
> /bin/su is a stone-age program and should not be used for *anything* IMHO.

I was just giving idea and not taking about security of specifics.

>> You can set the sudo policy so that it does not require asking for password.
>
> If you really allow anybody to run /bin/su in /etc/sudoers, then sorry but
> you deserve to get rooted. :-/

I didn't write that. If you want a specific example, then what I meant was

[user-that-run-flask]    ALL=(ALL) NOPASSWD:/bin/mv

Re: [flask] how to dropping privileges for different requests?

From:
Artem Chekunov
Date:
2014-11-17 @ 14:51
i found solution
i'll do a separate rpyc server with forking mode
and i will work with remote objects


On Mon, Nov 17, 2014 at 11:14 AM, Charles <peacech@gmail.com> wrote:

> On Mon, Nov 17, 2014 at 2:52 PM, Matthias Urlichs <matthias@urlichs.de>
> wrote:
> > Hi,
> >
> > Charles:
> >> Another idea: run 'sudo su <username> mv /tmp/uploaded_file
> >> /home/username/target'
> >>
> > No, you run "sudo -u <username> <whatever>" and specifically allow your
> web
> > user to run "whatever" on any user.
> >
> > Also, "whatever" should be a script which checks that (a) the UID is of
> an
> > ordinary user, (b) the destination doesn't exist and (c) is within the
> > user's $HOME, (d) the source belongs to the web user, is not a symlink,
> > is in your temporary upload directory and not e.g. /etc/shadow, (e) you
> > have been called by the web user and not Joe Script Kiddie, (f) …
> > Directly using /bin/mv is not adequate; if you do that you might as well
> > run the whole web server as root.
> >
> > Also², "su" is completely superfluous here.
> > It doesn't even work the way you think it does:
> >
> > # strace -f -eexecve su root /bin/cat /dev/null
> > execve("/bin/su", ["su", "root", "/bin/cat", "/dev/null"], [/* 25 vars
> */]) = 0
> > Process 32032 attached
> > [pid 32032] execve("/bin/bash", ["bash", "/bin/cat", "/dev/null"], [/*
> 29 vars */]) = 0
> > /bin/cat: /bin/cat: cannot execute binary file
> > #
> >
> > /bin/su is a stone-age program and should not be used for *anything*
> IMHO.
>
> I was just giving idea and not taking about security of specifics.
>
> >> You can set the sudo policy so that it does not require asking for
> password.
> >
> > If you really allow anybody to run /bin/su in /etc/sudoers, then sorry
> but
> > you deserve to get rooted. :-/
>
> I didn't write that. If you want a specific example, then what I meant was
>
> [user-that-run-flask]    ALL=(ALL) NOPASSWD:/bin/mv
>



-- 
Best Regards
Artem Chekunov

Web: http://about.me/achekunov
Email: scorp.dev.null@gmail.com
Cell phone: +7 921 564 0576
Skype: scorpius_new
Jabber: scorp.dev.null@gmail.com

Re: [flask] how to dropping privileges for different requests?

From:
Lars Hansson
Date:
2014-11-17 @ 08:11
In addition to what Matthias said, the user <username> should be set
in sudoers to ONLY be allowed to run <whatever>.


On Mon, Nov 17, 2014 at 3:52 PM, Matthias Urlichs <matthias@urlichs.de> wrote:
> Hi,
>
> Charles:
>> Another idea: run 'sudo su <username> mv /tmp/uploaded_file
>> /home/username/target'
>>
> No, you run "sudo -u <username> <whatever>" and specifically allow your web
> user to run "whatever" on any user.
>
> Also, "whatever" should be a script which checks that (a) the UID is of an
> ordinary user, (b) the destination doesn't exist and (c) is within the
> user's $HOME, (d) the source belongs to the web user, is not a symlink,
> is in your temporary upload directory and not e.g. /etc/shadow, (e) you
> have been called by the web user and not Joe Script Kiddie, (f) …
> Directly using /bin/mv is not adequate; if you do that you might as well
> run the whole web server as root.
>
> Also², "su" is completely superfluous here.
> It doesn't even work the way you think it does:
>
> # strace -f -eexecve su root /bin/cat /dev/null
> execve("/bin/su", ["su", "root", "/bin/cat", "/dev/null"], [/* 25 vars */]) = 0
> Process 32032 attached
> [pid 32032] execve("/bin/bash", ["bash", "/bin/cat", "/dev/null"], [/* 
29 vars */]) = 0
> /bin/cat: /bin/cat: cannot execute binary file
> #
>
> /bin/su is a stone-age program and should not be used for *anything* IMHO.
>
>> You can set the sudo policy so that it does not require asking for password.
>
> If you really allow anybody to run /bin/su in /etc/sudoers, then sorry but
> you deserve to get rooted. :-/
>
> --
> -- Matthias Urlichs

Re: [flask] how to dropping privileges for different requests?

From:
Charles
Date:
2014-11-17 @ 07:02
On Mon, Nov 17, 2014 at 2:01 PM, Charles <peacech@gmail.com> wrote:
> On Thu, Nov 13, 2014 at 7:03 PM, Artem Chekunov
> <scorp.dev.null@gmail.com> wrote:
>>
>> because if one of some requests will crushed, file in user home directory
>> will have owner root
>>
>> anyway main goal is each request should handled within user context
>
> Another idea: run 'sudo su <username> mv /tmp/uploaded_file
> /home/username/target'

Sorry, I think that should be cp not mv, and then delete the temporary
file from the python code.

Re: [flask] how to dropping privileges for different requests?

From:
Daniel Neuhäuser
Date:
2014-11-13 @ 12:33
Don't run your application as root. Run it as a user with as few 
privileges as possible, outsource tasks that require additional privileges
to other processes. 

Store the files in an application specific directory with subdirectories 
for each user.

Have a separate independent process watch the directory and moves complete
files to the users home directory. 


> Am 13.11.2014 um 13:03 schrieb Artem Chekunov <scorp.dev.null@gmail.com>:
> 
> 
> because if one of some requests will crushed, file in user home 
directory will have owner root
> 
> anyway main goal is each request should handled within user context
> 
>  
>> 
>> Why not just chown the uploaded files after saving it?
> 
> 
> 

Re: [flask] how to dropping privileges for different requests?

From:
Matthias Urlichs
Date:
2014-11-13 @ 11:40
Hi,

Charles:
> > any ideas?
> 
> Why not just chown the uploaded files after saving it?

"Just chown" implies that the Flask app runs with root privileges.
Don't Do That.

I'd write a small setuid helper which your Flask app can talk to, with RPyC
or similar, passing in a file name and a user. The helper would move the
file (making sure not to overwrite anything, not to write to dotted
directories, etc.) and chown it to the user.

If you use gevent instead of forking or threading, an adapter for RPyC is here:


https://raw.githubusercontent.com/smurfix/playground/master/Pinako/geventrpyc/__init__.py

Anyway, that's the complicated solution. The simple solution is to force
the user to create a directory that's writeable by your Flask app.
(Or a script that does this for every user …)

-- 
-- Matthias Urlichs