如何验证urllib2脚本以便从Django站点访问HTTPS Web服务?

car*_*ard 4 python django https web-services urllib2

每一个人.我正在开发一个django/mod_wsgi/apache2网站,该网站使用https为所有请求和响应提供敏感信息.如果用户未经过身份验证,则会写入所有视图以进行重定向.它还有几个视图,其功能类似于RESTful Web服务.

我现在正在编写一个脚本,使用urllib/urllib2来联系其中的几个服务,以便下载一系列非常大的文件.我在尝试登录时遇到403:FORBIDDEN错误的问题.

我用于身份验证和登录的(粗略草稿)方法是:

def login( base_address, username=None, password=None ):

    # prompt for the username (if needed), password
    if username == None:
        username = raw_input( 'Username: ' )
    if password == None:
        password = getpass.getpass( 'Password: ' )
    log.info( 'Logging in %s' % username )

    # fetch the login page in order to get the csrf token
    cookieHandler = urllib2.HTTPCookieProcessor()
    opener = urllib2.build_opener( urllib2.HTTPSHandler(), cookieHandler )
    urllib2.install_opener( opener )

    login_url = base_address + PATH_TO_LOGIN
    log.debug( "login_url: " + login_url )
    login_page = opener.open( login_url )

    # attempt to get the csrf token from the cookie jar
    csrf_cookie = None
    for cookie in cookieHandler.cookiejar:
        if cookie.name == 'csrftoken':
             csrf_cookie = cookie
             break
    if not cookie:
        raise IOError( "No csrf cookie found" )
    log.debug(  "found csrf cookie: " + str( csrf_cookie ) )
    log.debug(  "csrf_token = %s" % csrf_cookie.value )

    # login using the usr, pwd, and csrf token
    login_data = urllib.urlencode( dict(
        username=username, password=password,
        csrfmiddlewaretoken=csrf_cookie.value ) )
    log.debug( "login_data: %s" % login_data )

    req = urllib2.Request( login_url, login_data )
    response = urllib2.urlopen( req )
    # <--- 403: FORBIDDEN here

    log.debug( 'response url:\n' + str( response.geturl() ) + '\n' )
    log.debug( 'response info:\n' + str( response.info() ) + '\n' )

    # should redirect to the welcome page here, if back at log in - refused
    if response.geturl() == login_url:
        raise IOError( 'Authentication refused' )

    log.info( '\t%s is logged in' % username )
    # save the cookies/opener for further actions
    return opener 
Run Code Online (Sandbox Code Playgroud)

我正在使用HTTPCookieHandler在脚本端存储Django的身份验证cookie,因此我可以访问Web服务并完成重定向.

我知道如果我没有传递csrf令牌以及登录信息,那么Django的CSRFmiddleware会让我失望,所以我首先从第一页/表单load的cookiejar中取出它.就像我提到的,这适用于网站的http /开发版本.

具体来说,我试图通过https连接将凭据发布到登录页面/表单时获得403.在使用http连接的开发服务器上使用时,此方法有效.

没有Apache目录指令阻止访问该区域(我可以看到).该脚本成功连接到没有发布数据的登录页面,所以我认为这会让Apache摆脱问题(但我可能是错的).

我正在使用的python安装都使用SSL编译.

我还读到urllib2不允许通过代理进行https连接.我对代理不是很熟悉,所以我不知道使用远程机器上的脚本实际上是代理连接,是否会出现问题.这会导致访问问题吗?

据我所知,问题在于cookie和帖子数据的组合,但我不知道从哪里拿到它.

任何帮助,将不胜感激.谢谢

car*_*ard 5

请原谅我回答我自己的问题,但是 - 为了记录,这似乎解决了它:

事实证明,我需要将HTTP Referer标头设置为我发布登录信息的请求中的登录页面URL.

req.add_header( 'Referer', login_url )
Run Code Online (Sandbox Code Playgroud)

原因在Django CSRF文档中进行了解释- 特别是第4步.

由于我们有点特殊的服务器设置,我们在生产端使用HTTPS而DEBUG = False,我没有看到csrf_failure失败的原因(在这种情况下:'Referer check failed - no referer')通常在调试信息.我最终将这个失败原因打印到Apache error_log和STFW'd上.这导致我使用code.djangoproject /.../ csrf.py和Referer头修复.