为什么Selenium会导致CSRF 403?

时间:2015-08-10 21:42:32

标签: django selenium cookies csrf django-csrf

我正在尝试使用Django和Selenium创建一个简单的登录测试,但由于CSRF失败而获得403。我期待中间件在GET请求中添加cookie,然后在POST上解析它。

这是我到目前为止所检查的内容:

1。 Cookie是否在GET请求中设置为/accounts/login/

  

是的,Cookie正在process_response方法

中设置

2。是否可以在Selenium驱动程序上使用cookie?

  

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。在POST请求期间找到了cookie吗?

  

不,这个尝试/除了django.middleware.CsrfViewMiddleware.process_view失败了:

source

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()

问题

我可以尝试下一步调试它吗?

1 个答案:

答案 0 :(得分:1)

老问题,但在坚持了几个小时之后,答案很简单。

来自docs:

  

如果浏览器最初通过HTTP连接,则默认为   大多数浏览器都可能泄露现有的cookie。对于   这个原因,你应该设置你的SESSION_COOKIE_SECURE和   CSRF_COOKIE_SECURE设置为True。这指示浏览器   仅通过HTTPS连接发送这些cookie。请注意,这将   表示会话不能通过HTTP和CSRF保护   将阻止通过HTTP接受任何POST数据(这将是   如果要将所有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 = 'name@names.com'
        self.password = 'strange decisions...'
        get_user_model().objects.create_user(self.username, self.username, self.password)
        self.browser = webdriver.Firefox()

这应该会停止CSRF验证问题。