Python笔记:Django框架的静态文件访问、CSRF、状态保持、中间件、密码管理

静态文件

  • 项目中的CSS、图片、js都是静态文件
  • 备注:本文基于django版本1.11展开, 技术栈会有所升级, 仅供参考!

1 ) 配置静态文件

  • 在settings 文件中定义静态内容

    STATIC_URL = '/static/'
    STATICFILES_DIRS = [
        os.path.join(BASE_DIR, 'static'),
    ]
    
  • 在项目根目录下创建static目录,再创建当前应用名称的目录

    • mysite/static/myapp/
  • 在模板中可以使用硬编码

    • /static/my_app/myexample.jpg
  • 在模板中可以使用static编码

    { % load static from staticfiles % }
    <img src="{ % static "app/myexample.jpg" % }" alt="My image"/>
    

Csrf

  • CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本XSS,但它与XSS非常不同,XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性

  • CSRF中间件和模板标签为防止跨站点请求伪造提供了易用的保护。

  • 当恶意网站包含链接,表单按钮或某些旨在在您的网站上执行某些操作的JavaScript时,会使用在浏览器中访问恶意网站的登录用户的凭据进行此类攻击。

  • 还介绍了一种相关攻击类型,即“登录CSRF”,攻击网站欺骗用户的浏览器,以便使用其他人的凭证登录到网站。

1 ) csrf的使用

  • 在django的模板中,提供了防止跨站攻击的方法
    • 在settings.py中启用’django.middleware.csrf.CsrfViewMiddleware’中间件,此项在创建项目时,默认被启用
    • 在HTML的表单中添加标签
      <form>
      { % csrf_token % }
      ...
      </form>
      

2 ) 取消保护

  • 如果某些视图不需要保护,可以使用装饰器csrf_exempt,模板中也不需要写标签,修改csrf2的视图如下
    from django.views.decorators.csrf import csrf_exempt
    
    @csrf_exempt 
    def csrf2(request):
        uname=request.POST['uname'] 
        return render(request,'booktest/csrf2.html',{'uname':uname}) 
        运行上面的两个请求,发现都可以请求
    

3 ) 保护原理

  • 加入标签后,可以查看源代码,发现多了如下代码
    <input type='hidden' name='csrfmiddlewaretoken' value='nGjAB3Md9ZSb4NmG1sXDolPmh3bR2g59' />
    
  • 在浏览器的调试工具中,可以查看cookie信息
  • 查看跨站的信息,并没有cookie信息,即使加入上面的隐藏域代码,发现又可以访问了
  • 结论:django的csrf不是完全的安全
  • 当提交请求时,中间件django.middleware.csrf.CsrfViewMiddleware会对提交的cookie及隐藏域的内容进行验证,如果失败则返回403错误

4 ) Ajax CSRF 认证

  • GET 请求不需要 CSRF 认证,POST 请求需要正确认证才能得到正确的返回结果。
  • 如果使用Ajax调用的时候,就要麻烦一些。需要注意以下几点:
    • 在视图中使用render (而不要使用 render_to_response)
    • 使用 jQuery 的 ajax 或者 post 之前 加入这个 js 代码
      jQuery(document).ajaxSend(function(event, xhr, settings) {
          function getCookie(name) {
              var cookieValue = null;
              if (document.cookie && document.cookie != '') {
                  var cookies = document.cookie.split(';');
                  for (var i = 0; i < cookies.length; i++) {
                      var cookie = jQuery.trim(cookies[i]);
                      // Does this cookie string begin with the name we want?
                      if (cookie.substring(0, name.length + 1) == (name + '=')) {
                          cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                          break;
                      }
                  }
              }
              return cookieValue;
          }
          function sameOrigin(url) {
              // url could be relative or scheme relative or absolute
              var host = document.location.host; // host + port
              var protocol = document.location.protocol;
              var sr_origin = '//' + host;
              var origin = protocol + sr_origin;
              // Allow absolute or scheme relative URLs to same origin
              return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
                  (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
                  // or any other URL that isn't scheme relative or absolute i.e relative.
                  !(/^(\/\/|http:|https:).*/.test(url));
          }
          function safeMethod(method) {
              return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
          }
      
          if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
              xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
          }
      });
      
  • 或者 更为优雅简洁的代码(不能写在 .js 中,要直接写在模板文件中):
    $.ajaxSetup({
        data: {csrfmiddlewaretoken: '{ { csrf_token } }' },
    });
    
  • 这样之后,就可以像原来一样的使用 jQuery.ajax() 和 jQuery.post()了

状态保持

  • HTTP协议是无状态的:每次请求都是一次新的请求,不会记得之前通信的状态
  • 客户端与服务器端的一次通信,就是一次会话
  • 实现状态保持的方式:在客户端或服务器端存储与会话有关的数据
  • 存储方式包括cookie、session,会话一般指session对象
  • 使用cookie,所有数据存储在客户端,注意不要存储敏感信息
  • 推荐使用sesison方式,所有数据存储在服务器端,在客户端cookie中存储session_id
  • 状态保持的目的是在一段时间内跟踪请求者的状态,可以实现跨页面访问当前请求者的数据
  • 注意:不同的请求者之间不会共享这个数据,与请求者一一对应

1 ) 开启session

  • 使用django-admin startproject创建的项目默认启用
  • 禁用会话:删除下面指定的两个值,禁用会话将节省一些性能消耗
  • Django 中session需要依赖数据库,因此需要确认数据库中是否存在 与session相关的 表
  • 在settings.py文件中
    • INSTALLED_APPS列表中添加:‘django.contrib.sessions’
    • MIDDLEWARE_CLASSES列表中添加:‘django.contrib.sessions.middleware.SessionMiddleware’

2 ) 使用session

  • 启用会话后,每个HttpRequest对象将具有一个session属性,它是一个类字典对象
  • get(key, default=None):根据键获取会话的值
  • clear():清除所有会话
  • flush():删除当前的会话数据并删除会话的Cookie
  • del request.session[‘member_id’]:删除会话
  • 示例:
    #session设置
    request.session[key] = value
    
    #session获取
    request.session.get(key,default=Node)
    
    #session删除
    
    # 删除单个key 不存在时报错
    del request.session['a'] 
    
    #清除所有会话,但不会删除数据
    request.session.clear() 
    
    #删除当前的会话数据
    request.session.flush()
    

中间件

  • 中间件是一个轻量级、底层的插件系统,可以介入Django的请求和响应处理过程,修改Django的输入或输出
  • 激活:添加到Django配置文件中的MIDDLEWARE_CLASSES元组中
  • 使用中间件,可以干扰整个处理过程,每次请求中都会执行中间件的这个方法

1 ) 验证用户是否登陆示例

  • 在应用中创建AdminLoginMiddleware.py文件
    class AppMiddleware:
        def __init__(self, get_response):
            self.get_response = get_response
            print('middleware init!')
    
        def __call__(self, request):
            print('middleware call!')
            response = self.get_response(request)
            return response
    

2 ) 配置中间件

  • 在settings.py文件中修改MIDDLEWARE_CLASSES选项
    MIDDLEWARE = [
        #自定义的中间件
        'app.app_middleware.AppMiddleware'
    ]
    

使用Django中提供的密码方案

  • 该django.contrib.auth.hashers模块提供了一组函数来创建和验证散列密码。您可以独立于User模型使用它们。
    # from django.contrib.auth.hashers import make_password, check_password
    # 对密码进行加密操作
    # upass = make_password(request.POST['password'], None, 'pbkdf2_sha256')
    # print(upass) # 这里是加密后的密码
    # b = check_password('1234567','pbkdf2_sha256$36000$197nqXM6yxYv$Zxh/Vsns8qszkvUmY81BgrjCeLPXhCHLEilP6VO+Rnc=')
    # print(b) # False 备注:check_password的参数:第一个是加密前的数据, 第二个是加密后的数据
    
    # python中的MD5加密
    # 获取密码并md5
    import hashlib
    from django.http  import HttpResponse
    
    m = hashlib.md5()
    m.update(bytes(request.POST['password'], encoding="utf8"))
    str = m.hexdigest()
    return HttpResponse("123456的md5是:" + str)
    

相关代码示例

  • 城市联动
  • 文件上传
  • 分页
  • 富文本编辑器
  • session状态维持
  • 中间件
  • 密码管理
  • 示例详见代码仓库
发布了417 篇原创文章 · 获赞 228 · 访问量 70万+

猜你喜欢

转载自blog.csdn.net/Tyro_java/article/details/104350118
今日推荐