Почему Selenium вызывает CSRF 403?

Я пытаюсь создать простой тест входа в систему, используя Django и Selenium, но получаю 403 из-за сбоя CSRF. Я ожидаю, что промежуточное ПО добавит файл cookie в запрос GET, а затем проанализирует его обратно в POST.

Вот что я проверил до сих пор:

<сильный>1. Устанавливается ли для файла cookie в запросе GET значение /accounts/login/?

Да, cookie устанавливается в методе process_response

<сильный>2. Доступен ли файл cookie в драйвере Selenium?

Да

ipdb> self.selenium.get_cookies()
[{u'domain': u'localhost', u'name': u'csrftoken', u'value': u'DzNbEn9kZw0WZQ4OsRLouriFN5MOIQos', u'expiry': 1470691410, u'path': u'/', u'httpOnly': False, u'secure': True}]

<сильный>3. Обнаружен ли файл cookie во время POST-запроса?

Нет, эта попытка/кроме из django.middleware.CsrfViewMiddleware.process_view не удалась:

источник

try:
    csrf_token = _sanitize_token(
        request.COOKIES[settings.CSRF_COOKIE_NAME])
    # Use same token next time
    request.META['CSRF_COOKIE'] = csrf_token
except KeyError:
    csrf_token = None
    # Generate token and store it in the request, so it's
    # available to the view.
    request.META["CSRF_COOKIE"] = _get_new_csrf_key()

Код

class TestLogin(StaticLiveServerTestCase):

    @classmethod
    def setUpClass(cls):
        cls.selenium = getattr(webdriver, settings.SELENIUM_WEBDRIVER)()
        cls.selenium.maximize_window()
        cls.selenium.implicitly_wait(5)

        super(TestLogin, cls).setUpClass()

    @classmethod
    def tearDownClass(cls):
        cls.selenium.quit()

        super(TestLogin, cls).tearDownClass()

    def test_login(self):

        self.selenium.get('{}{}'.format(self.live_server_url, '/accounts/login/?next=/'))
        assert "Django" in self.selenium.title
        un_el = self.selenium.find_element_by_id('id_username').send_keys('the_un')
        pw_el = self.selenium.find_element_by_id('id_password')
        pw_el.send_keys('the_pw')
        pw_el.send_keys(Keys.RETURN)

        try:
            WebDriverWait(self.selenium, 5).until(EC.title_contains("New Title"))
        except TimeoutException as e:
            msg = "Could not find 'New Title' in title. Current title: {}".format(self.selenium.title)
            raise TimeoutException(msg)
        finally:
            self.selenium.quit()

Вопрос

Что я могу попробовать дальше, чтобы отладить это?


person Brian Dant    schedule 10.08.2015    source источник


Ответы (1)


Старый вопрос, но после того, как я застрял с этим на несколько часов, ответ был прост.

Из документов:

Если браузер первоначально подключается через HTTP, который используется по умолчанию для большинства браузеров, возможна утечка существующих файлов cookie. По этой причине вы должны установить для параметров SESSION_COOKIE_SECURE и CSRF_COOKIE_SECURE значение True. Это указывает браузеру отправлять эти файлы cookie только через соединения HTTPS. Обратите внимание, что это будет означать, что сеансы не будут работать через HTTP, а защита CSRF предотвратит прием любых данных POST через HTTP (что будет нормально, если вы перенаправляете весь HTTP-трафик на HTTPS).

Как и я, вы, вероятно, используете django_extensions + Werkzeug для большей части вашей работы, и по умолчанию вся ваша локальная работа выполняется через SSL.

Если вы используете версию unittest или Djangos, я бы рекомендовал вам изменить эти настройки во время выполнения теста, например так:

...
from django.conf import settings

class ProfilePagetest(LiveServerTestCase):

    def setUp(self):

        settings.CSRF_COOKIE_SECURE = False
        settings.SESSION_COOKIE_SECURE = False

        self.url = reverse('clientpage:profile')
        self.username = '[email protected]'
        self.password = 'strange decisions...'
        get_user_model().objects.create_user(self.username, self.username, self.password)
        self.browser = webdriver.Firefox()

Это должно остановить проблемы с проверкой CSRF.

person Jamie S    schedule 17.11.2015
comment
Я бы использовал декоратор djangos override_settings, чтобы гарантировать сброс настроек после выполнения теста. docs.djangoproject.com/en/1.9/topics /тестирование/инструменты/ - person ex-zac-tly; 03.03.2016