1

Django サイトで Github 経由で認証しようとしています。これは私が思いついたものです:

import string
import random
import urllib

from django.conf import settings
from django.core.urlresolvers import reverse
from django.shortcuts import redirect
from django.utils.crypto import constant_time_compare
from django.contrib.auth import login

from rauth import OAuth2Service
from mongoengine.django.auth import User

from utils import make_absolute


SESSION_KEY = '_oauth_access_token'
SESSION_STATE = '_oauth_state'

github = OAuth2Service(
    client_id=settings.GITHUB_APP_ID,
    client_secret=settings.GITHUB_API_SECRET,
    name='github',
    authorize_url='https://github.com/login/oauth/authorize',
    access_token_url='https://github.com/login/oauth/access_token',
    base_url='http://github.com/')


def random_string():
    return ''.join(random.choice(string.ascii_letters + string.digits)
                   for _ in xrange(random.randint(27, 49)))


def flush_and_set(request, key, value):
    if key in request.session:
        if request.session[key] != value:
            request.session.flush()
    else:
        request.session.cycle_key()
    request.session[key] = value


def start_pipeline(request):
    state = random_string()
    flush_and_set(request, SESSION_STATE, state)
    return redirect(github.get_authorize_url(
                        redirect_uri=make_absolute(reverse('auth-pipeline-end')),
                        state=state))


def end_pipeline(request):
    if not constant_time_compare(request.session[SESSION_STATE],
                                 request.GET['state']):
        return redirect('home')
    session = github.get_auth_session(data={'code': request.GET['code'],
                                            'redirect_uri':
                                            make_absolute(reverse('home'))})
    flush_and_set(request, SESSION_KEY, session.access_token)
    user_data = session.get('https://api.github.com/user?' +
                            urllib.urlencode({'access_token':
                                              session.access_token})).json()
    username = user_data['login']
    try:
        user = User.objects.get(username=username)
    except User.DoesNotExist:
        user = User(username=username)
    for field in ('email',):
        d = user_data[field]
        if d:
            setattr(user, field, d)
    user.backend = 'mongoengine.django.auth.MongoEngineBackend'
    user.save()
    login(request, user)
    return redirect('home')

2 つの質問があります。

  1. このようにして安全で安全ですか?
  2. セッションに有効期限を設定する必要がありますか? 今のままでは、期限切れになることはないように思われるからです。

注: rauth も使用しています: https://rauth.readthedocs.org/en/latest/

4

1 に答える 1

1

可能な限り安全ではなく、いくつかの詳細が欠けています.

    • より安全な状態値を得るにはSystemRandomを使用してください。
    • セッションはCookie ベースですか? それらはデフォルトではありませんし、そうであってはなりません。
    • リダイレクトは HTTPS によって保護されていますか?
    • GitHub へのすべてのリクエストは HTTPS 経由ですか? トークンも取得後?
  1. デフォルトの有効期限は 2 週間ですが、OAuth 2 アクセス トークンは通常、それよりもずっと早く期限切れになります。ただし、GitHub トークンは期限切れにならないので、閉じるときにセッションを期限切れにし、不要になったらトークンを削除することで改善されると思います。

とは言うものの、独自の GitHub ログインをロールバックする代わりにpython-social-authを使用することを強くお勧めします。なぜなら、そのプロジェクトにはより多くの注目が集まっており、しばらくの間そうであったからです。

于 2013-09-13T15:47:33.673 に答える