开发者

Looking for advice to secure a private REST API written in python-flask

开发者 https://www.devze.com 2023-03-31 14:46 出处:网络
I am currently writing a rest API in python with the microframework Flask. It\'s a private API and it deals with user data. I plan to use this API to build a web and an Android app.

I am currently writing a rest API in python with the microframework Flask. It's a private API and it deals with user data. I plan to use this API to build a web and an Android app.

For now I use digest auth to secure private user data. For example if you want to post data on my service with the user bob you make a post request at myapi/story/create and provide bob's credentials with the digest pattern.

I am aware this is not a good solution because :

-Digest auth is not secure

-The client is not authenticated (How to secure requests not related with current user, for example create a new user ?)

I read a lot of stuff about oAuth but the 3-legged authentication seems overkill because I don't plan to open my API to third party.

The 2-legged oAuth won't fit because it only provides authentification for clients and not for users.

Another problem with oAuth is that I haven't found a comprehensiv开发者_Python百科e guide for implementing it in Python. I found the python-oauth2 library, but I don't understand the server example and I can't find additional documentation. Plus it seems that many aspects of oAuth are not covered in this example.

So my questions are :

  1. Is there alternative scheme (not oAuth) for authenticate both client and user with a reasonable level of security ?
  2. If oAuth is the best solution :
    • How to skip the authorization process (because users won't have to authorize third party clients)?
    • Is there detailled documentation for python-oauth2 or for any other Python library?

Any help or advice will be appreciated.


The simple answer is to expose your API via HTTPS only, and then use HTTP Basic authentication. I don't think there's really any reason to bother with Digest. Basic authentication is insecure, but is submitted with every request so you never need to worry about your authentication going stale or whatever. By tunneling it over HTTPS, you have a secure connection.

If you want to authenticate the client, you could use SSL client certificates. That said, in general it's pretty tough to really lock down the client against malicious users, so I would consider making the sign-up functions openly accessible and protect yourself from DOS etc via out-of-band account verification.


Have you already considered to use the Basic Authentication?

I haven't used yet the framework you mentioned, but I used the basic auth to protect some urls in an app based on web.py and worked fine.

Basically, you can use a token in base64 which is actually a standard http heeader.

Maybe this example can help you:

class Login:

    def GET(self):
        auth = web.ctx.env.get('HTTP_AUTHORIZATION')
        authreq = False
        if auth is None:
            authreq = True
        else:
            auth = re.sub('^Basic ','',auth)
            username,password = base64.decodestring(auth).split(':')
            if (username,password) in settings.allowed:
                raise web.seeother('/eai')
            else:
                authreq = True
        if authreq:
            web.header('WWW-Authenticate','Basic realm="Auth example"')
            web.ctx.status = '401 Unauthorized'
            return


If you are interested in basic authentication, here is a quick attribute which you can use to decorate your handlers http://www.varunpant.com/posts/basic-authentication-in-web-py-via-attribute. This example is primarily written in web.py context, but I guess it can be easily tweaked.

def check_auth(username, password): 
    return username == 'username' and password == 'password'


def requires_auth(f):
    @wraps(f)     
    def decorated(*args, **kwargs):        
        auth = web.ctx.env['HTTP_AUTHORIZATION'] if 'HTTP_AUTHORIZATION' in  web.ctx.env else None
        if auth:
            auth = re.sub('^Basic ', '', auth)
            username, password = base64.decodestring(auth).split(':')
        if not auth or not check_auth(username, password):
            web.header('WWW-Authenticate', 'Basic realm="admin"')
            web.ctx.status = '401 Unauthorized'
            return 

        return f(*args, **kwargs)

    return decorated
0

精彩评论

暂无评论...
验证码 换一张
取 消