Проблемы безопасности со страницей промежуточного программного обеспечения - PullRequest
10 голосов
/ 20 июня 2011

Когда мой автозапуск находится в темном режиме, я хочу, чтобы все, кроме доступа к /, переходили на страницу проверки, где пользователи вводят пароль, предоставленный им представителем. Я предложил следующее простое промежуточное программное обеспечение для выполнения задачи. Просто чтобы прояснить, это предназначено для того, чтобы пользователи согласились сохранять конфиденциальность сайта, прежде чем им разрешат просматривать его, а не использовать в качестве системы безопасности или клона .htaccess. Однако я хотел бы запретить им видеть какие-либо общедоступные страницы (то есть те, которые не украшены @login_required), не зная пароля на экран. Функция password_check использует Django Auth для генерации хэша входного пароля для проверки значения db.

Какие мысли / техники обхода, которые вы, ребята, видите? Одна из моих идей заключалась в том, чтобы изменить функцию входа в систему, чтобы LicenceKey вставлялся в сеанс недавно вошедших в систему пользователей, вместо того, чтобы давать зарегистрированным пользователям исключение. Однако, поскольку они могут только создать новый сеанс, войдя в систему, и для входа в систему требуется согласие на проверку, это кажется излишним.

Обратная связь приветствуется.

Промежуточное программное обеспечение выглядит так:

from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
import re

class LicenceScreener(object):
    SCREENER_PATH = reverse("licence")
    INDEX_PATH = reverse("index")
    LICENCE_KEY = "commercial_licence"
    def process_request(self, request):
        """ Redirect any access not to the index page to a commercial access screener page
            When the screener form is submitted, request.session[LICENCE_KEY] is set.
        """
        if not LicenceScreener.LICENCE_KEY in request.session \
            and not request.user.is_authenticated() \
            and LicenceScreener.SCREENER_PATH != request.path\
            and LicenceScreener.INDEX_PATH != request.path:
                return HttpResponseRedirect(self.SCREENER_PATH)

И вид выглядит так:

def licence(request):
    c = RequestContext(request, {}  )
    if request.method == 'POST':
        form = LicenceAgreementForm(request.POST)
        if form.is_valid():
            if password_check(form.cleaned_data["password"]):
                request.session[LicenceScreener.LICENCE_KEY] = True
                return HttpResponseRedirect(reverse("real-index"))
            else:
                form._errors["password"] = form.error_class([_("Sorry that password is incorrect")])    
    else:
        form = LicenceAgreementForm()  
    c["form"] = form        
    return render_to_response('licence.html',c)

РЕДАКТИРОВАТЬ 1. Удалены регулярные выражения в соответствии с предложением Тобу

1 Ответ

1 голос
/ 11 июля 2011

Вот мое решение.Он использует не COOKIES, а пользовательский Auth Backend.

Шаг 1

Хорошо иметь приложение Django для этого:

key_auth/
    templates/
        key_auth_form.html # very simple form template
    __init__.py
    models.py
    urls.py
    views.py
    forms.py
    middleware.py
    backend.py

settings.py :

INSTALLED_APPS = (
    # ...
    'key_auth',
)

Шаг 2

Нам нужна Модель для хранения ваших токенов. models.py :

from django.db import models
from django.contrib.auth.models import User

class SecurityKey(models.Model):
    key = models.CharField(max_length=32, unique=True)
    user = models.OneToOneField(User)

Примечание : В моем простом решении вам нужно будет вручную создавать и синхронизировать новых пользователей и их ключи SecurityKeys.Но вы можете улучшить это в будущем.

Шаг 3

Нам понадобится пользовательское Промежуточное программное обеспечение , которое потребует аутентификацию от всех пользователей на всех страницах (кроме нескольких специальныхстраниц ).Вот middleware.py :

from django.contrib.auth.decorators import login_required
from django.core.urlresolvers import reverse

class KeyAuthMiddleware(object):
    def process_view(self, request, view_func, view_args, view_kwargs):
        login_url = reverse('key_auth_login') # your custom named view

        # Exceptional pages
        login_page = request.path.find(login_url) == 0
        logout_page = request.path.find(reverse('logout')) == 0
        admin_page = request.path.find(reverse('admin:index')) == 0 # I've excluded Admin Site urls

        if not login_page and not logout_page and not admin_page:
            view_func = login_required(view_func, login_url=login_url)

        return view_func(request, *view_args, **view_kwargs)

Это промежуточное ПО будет перенаправлять неавторизованных пользователей на страницу 'key_auth_login' с формой авторизации.

Шаг 4

Вот urls.py , который отображает представление 'key_auth_login':

from django.conf.urls.defaults import patterns, url

urlpatterns = patterns('key_auth.views',
    url(r'^$', 'login_view', name='key_auth_login'),
)

И глобальный проект urls.py :

from django.contrib import admin
from django.conf.urls.defaults import patterns, include, url

admin.autodiscover()

urlpatterns = patterns('',
    url(r'^key_auth/$', include('key_auth.urls')),
    url(r'^logout/$', 'django.contrib.auth.views.logout', {'next_page': '/'}, name='logout'),
    url(r'^admin/', include(admin.site.urls)),
    url(r'^$', 'views.home_page'),
)

Как вы можете видеть - сайт администратора включен (поэтому вы также можете войти в систему как администратор).

Шаг 5

Вот наш взгляд ( views.py *)1058 *):

from django.contrib.auth import login
from django.views.generic.edit import FormView
from key_auth.forms import KeyAuthenticationForm

class KeyAuthLoginView(FormView):
    form_class = KeyAuthenticationForm
    template_name = 'key_auth_form.html'

    def form_valid(self, form):
        login(self.request, form.user)
        return super(KeyAuthLoginView, self).form_valid(form)

    def get_success_url(self):
        return self.request.REQUEST.get('next', '/')

login_view = KeyAuthLoginView.as_view()

Я не буду показывать 'key_auth_form.html', потому что это действительно простой шаблон формы, ничего особенного.Но я покажу класс формы

Шаг 6

Класс формы ( forms.py ):

from django import forms
from django.contrib.auth import authenticate

class KeyAuthenticationForm(forms.Form):
    key = forms.CharField('Key', help_text='Enter your invite/authorization security key')
    user = None

    def clean_key(self):
        key = self.cleaned_data['key']
        self.user = authenticate(key=key)
        if not self.user:
            raise forms.ValidationError('Please, enter valid security key!')
        return key

Как мы видим, аутентифицируем () использовал здесь.Этот метод попытается аутентифицировать пользователя с помощью существующих бэкэндов.

Шаг 7

Пользовательский бэкэнд аутентификации. backend.py :

from django.contrib.auth.models import User
from key_auth.models import SecurityKey

class KeyAuthBackend(object):
    def authenticate(self, key=None):
        try:
            return SecurityKey.objects.get(key=key).user
        except SecurityKey.DoesNotExist:
            return None

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

Это очень просто!Просто проверьте ключ (токен).Вот его установка ( settings.py ):

AUTHENTICATION_BACKENDS = (
    'key_auth.backends.KeyAuthBackend',
    'django.contrib.auth.backends.ModelBackend',
)

Второй оставлен для поддержания работы сайта администратора.

Резюме

Этоit!

  1. Любой запрос проходит через KeyAuthMiddleware
  2. KeyAuthMiddleware пропускает вход в систему, выход из системы и URL-адреса администратора ...
  3. ... и перенаправляет всех неавторизованных пользователей на страницу входа в систему с помощью token-auth (с формой входа в систему через токен)
  4. Эта форма проверяет «ключ» через django.contrib.auth.authenticate () method ...
  5. ... который пытается аутентифицировать пользователя с помощью пользовательского KeyAuthBackend аутентификационного бэкэнда
  6. Если аутентификация успешна и форма действительна, тогда пользовательский KeyAuthLoginView делает django.contrib.auth.login (пользователь) и перенаправляет на запрошенную страницу

Вы также можете использовать сайт администратора и войти /Выйти из системы без key_auth ckeck.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...