zoukankan      html  css  js  c++  java
  • 同源策略的解决方案

    同源策略的解决方案

    1.什么是XSS攻击,什么是CSRF,什么是CORS

    # 什么是XSS攻击
        跨站脚本攻击分为两种方式:反射型攻击(比如,一些含有恶意脚本的URL),持久型攻击(将恶意脚本提交到被攻击网站的数据库中)
    
    # 什么是CSRF攻击
        跨站请求伪造攻击:顾明思义,是攻击者通过跨站请求,以被攻击者的合法身份进行非法的操作。比如获取被攻击者的token信息进行一些转账操作。
        
    # 什么是CORS
        跨域资源共享(CORS),需要浏览器和服务器的同时支持,目前所有的浏览器都支持该功能,IE浏览器不得低于IE10。
        整个CORS的通信过程,都是浏览器自动完成的,不需要用户的参与。对于开发者来说,CORS通信和AJAX通信没有什么区别,浏览器一但发现了AJAX请求跨越,会自动添加一些附加的头信息,有时候还会多出一次的附加请求。
        因此实现CORS通信的关键是在服务器。
    

    说到跨域问题,就得提一下同源策略了

    2.什么是同源策略

        所谓`同源策略`,是由NetSPace提出的一个著名的安全策略。同源就是指协议、域名、端口号相同,浏览器处于安全方面的考虑,只允许本域名下的接口相互交互,不同源的客户端脚本在没有明确的授权情况下,不能读写对方的资源。
    

    假设有这么一个情况:A网站是一家银行,用户登录后又去浏览了一些其他网站(如,网站B),网站B如果可以从A网站中获用户登录时的Cookies信息,那么B网站的管理员是不是可以为所欲为了?

    3.CORS的实现流程

    浏览器将CORS请求分为两类请求:简单请求(simple request)和非简单请求(not-so-simple request)
    
    浏览器发出的CORS简单请求,只需要在头信息中增加一个Origin字段。
    
    浏览器发出的CORS非简单请求,需要在正式通信之前,增加一次HTTP查询请求,称为“预检”请求(preflight)。浏览器先询问服务器,当前网页的域名是否在服务器许可的名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到了肯定的回复,浏览器才会正式发出XMLHttpRquest请求,否则就报错
    

    4.CORS两种请求详解

    只要同时满足两个请求,就是简单请求

    # 请求方法是以下的几种方法
    HEAD
    GET
    POST
    
    # HTTP的头信息不超出以下几种字段:
    Accept
    Accept-Language
    Content-Language
    Last-Event-ID
    Content-Type
    只限于三个值
    application/x-www-form-urlencoded   multipart/form-data  text/plain
    

    凡是不同时满足以上的两种条件,就属于非简单请求。

    浏览器对于这两种请求的处理方式,是不一样的。

        对于简单请求,浏览器会发送一次请求,数据会到达浏览器,如果请求地址URL和浏览器不同源(或者不在浏览器允许的域范围内),就会报错。
    
        对于非简单的请求,会发送两次请求,第一次先发送预检请求,只有预检通过了才会发送第二次请求
    

    关于预检

    如果复杂请求是PUT请求,则服务端要设置允许某请求通过,否则的话预检不通过;
        Access-Control-Request-Method
    如果复杂请求设置了请求头,那么服务端要设置允许某请求头通过,否则预检不通过;
        Access-Control-Request-Headers
    

    支持跨域

    # 简单请求
    服务器设置响应头:Access-Control-Allow-Origin = '域名' 或 '*'
    # 非简单请求
    对于非简单请求,首先先会发送预检请求,预检请求后才会发送真实的数据
    
        “预检”请求时,允许请求方式则需服务器设置响应头:Access-Control-Request-Method
        “预检”请求时,允许请求头则需服务器设置响应头:Access-Control-Request-Headers
    

    5.同源策略演示

    请求发起者http://127.0.0.1:8004/test/ 向 http://127.0.0.1:8000/home/test/ 发送get请求(简单请求),收到数据后,判断不同源,则报错。

    请求发起者

    def test(request):
        return render(request, 'test.html')
    
    </head>
    <body>
    
    <button onclick="test()">点我</button>
    
    </body>
    
    <script>
    
        function test() {
            $.ajax({
                url:'http://127.0.0.1:8000/home/test/',
                type:'get',
                {#contentType:'application/json',#}
                {#data:JSON.stringify({'name':'lqz'}),#}
                success:function (data) {
                    console.log(data)
    
                }
            })
    
        }
    
    </script>
    

    请求响应者

    class TestView(APIView):
        def get(self, request, *args, **kwargs):
            dic = {'name': 'lqz'}
            print('lxx')
            return APIResponse()
    

    这时候,数据虽然会发送给8004端口的程序,但是由于浏览器存在同源策略,如果在8000中没有设置允许8004跨域的头部信息的话,则会报错:

    简单请求的跨域

    class TestView(APIView):
        def get(self, request, *args, **kwargs):
            dic = {'name': 'lqz'}
            print('lxx')
            return APIResponse(headers={"Access-Control-Allow-Origin": "http://127.0.0.1:8004"})  # 或者 {"Access-Control-Allow-Origin": "*"}
    

    非简单请求的跨越

    # 8004 向 8000 发送post请求,且Content-Type是'application/json'类型
    <script>
        function test() {
            $.ajax({
                url: 'http://127.0.0.1:8000/home/test/',
                type: 'post',
                contentType: 'application/json',
                data: JSON.stringify({'name': 'lqz'}),
                success: function (data) {
                    console.log(data)
    
                }
            })
        }
    </script>
    
    会发送两次请求,第一发送options请求,进行请求的预检
    def options(self, request, *args, **kwargs):
        print('我是 options')
        return APIResponse(headers={"Access-Control-Allow-Headers": "Content-Type",
                                    "Access-Control-Allow-Origin": "http://127.0.0.1:8004"})
    
    def post(self, request, *args, **kwargs):
        print('lqz')
        return APIResponse(headers={"Access-Control-Allow-Origin": "http://127.0.0.1:8004"})
    

    6.跨域请求的中间件

    # 低配版
    from django.utils.deprecation import MiddlewareMixin
    
    
    class CorsMiddleware(MiddlewareMixin):
        ALLOW_HOST = 'http://127.0.0.1:8004' # 可以放到配置文件中
    
        def process_response(self, request, response):
            response['Access-Control-Allow-Origin'] = self.ALLOW_HOST
            if request.method == 'OPTIONS':
                response['Access-Control-Allow-Headers'] = 'Content-Type'
            return response
    
    dev.py
    MIDDLEWARE = [
        ...
        'luffyapi.utils.corsmiddleware.CorsMiddleware',
    ]
    

    7.使用第三方的插件

    # 安装第三方的插件
    pip install django-cors-headers
    # 注册app
    corsheaders
    # 注册中间件
    'corsheaders.middleware.CorsMiddleware'
    MIDDLEWARE = [
        # 第三方 cors插件
        'corsheaders.middleware.CorsMiddleware',
        ...
    ]
    # 在dev.py中进行配置(可选择)
    CORS_ORIGIN_ALLOW_ALL = True # 选择不限制跨域访问 如果为True将不再使用白名单,默认为False
    
    CORS_ORIGIN_WHITELIST = (   # 选择放行的白名单(授权进行跨站点HTTP请求的来源列表)   
        'http://127.0.0.1:8004',
        'https://sub.example.com',
        r'^https://w+.example.com$', # 在有大量子域使用的情况下,可以使用正则
    )
    
    CORS_ALLOW_METHODS = (   # 允许跨域的方法
        "DELETE",
        "GET", 
        "OPTIONS", 
        "PATCH",
        "POST", 
        "PUT"
    )
    CORS_ALLOW_HEADERS = (   # 允许跨域的请求头
        "accept",
        "accept-encoding",
        "authorization",
        "content-type",
        "dnt",
        "origin",
        "user-agent",
        "x-csrftoken",
        "x-requested-with",
    )
    
    CORS_PREFLIFHT_MAX_AGE = 0
    客户端/浏览器可以缓存预检响应的秒数。如果该值为0(或任何错误值),则不会发送最大期限标头。默认为 86400(一天)
    
    CORS_ALLOW_CREDENTIALS
    如果为True,则将允许将cookie包含在跨站点HTTP请求中。默认为False。
    
    注意:在Django 2.1中,添加了SESSION_COOKIE_SAMESITE设置,'Lax'默认情况下设置为 ,这将防止Django的会话cookie跨域发送。更改它以None绕过此安全限制。
    
    

    8.前后台打通

    # 下载axios 
    pip install axios
    # 配置min.js文件
    import axios from 'axios'
    Vue.prototype.$axios = axios;
    

    home.vue

    <template>
        <div class="Home">
            <h1>我是主页</h1>
            <button @click="test">点我</button>
        </div>
    </template>
    
    <script>
        // @ is an alias to /src
        export default {
            name: 'Home',
            methods: {
                test() {
                    this.$axios.get('http://127.0.0.1:8000/home/test/').then(response => {
                        console.log(response.data)  # ES6新语法,支持=>函数
                    }).catch(errors => {
                        console.log(errors)
                    })
                }
            }
        }
    </script>
    
    
    """
    this.$axios.get('http://127.0.0.1:8000/home/home/'). 向某个地址发送get请求
      then(function (response) {  如果请求成功,返回的数据再response中
        console.log(response)
      }).catch(function (error) {
        console.log(error)
      })
    """
    

    index.js

    Vue.use(VueRouter)
    
      const routes = [
      {
        path: '/',
        name: 'Home',
        component: Home
      },
    ]
    

    App.vue

    <template>
        <div id="app">
            <router-view/>
        </div>
    </template>
    
    <style>
    
    </style>
    
    <script>
        export default {
            name: 'App',
            components: {}
        }
    </script>
    

    9 X-admin后台的安装

    # 创建superuser
    python manage.py createsuperuser
    

    原始的admin后台管理界面

    x-admin的下载

    pip install -U https://codeload.github.com/sshwsfc/xadmin/zip/django2 --default-timeout=1000
    

    注册apps

    INSTALLED_APPS = [
        # ...
        # xadmin主体模块
        'xadmin',
        # 渲染表格模块
        'crispy_forms',
        # 为模型通过版本控制,可以回滚数据
        'reversion',
    ]
    

    xadmin需要自己的数据库模型

    执行数据库迁移的命令
    python manage.py makemigrations
    python manage.py migrate
    

    主路由替换掉admin:主urls.py

    # xadmin的依赖
    import xadmin
    xadmin.autodiscover()
    # xversion模块自动注册需要版本控制的 Model
    from xadmin.plugins import xversion
    xversion.register_models()
    
    urlpatterns = [
        # ...
        path(r'xadmin/', xadmin.site.urls),
    ]
    

    修改标题

    import xadmin
    from xadmin import views
    
    class GlobalSettings(object):
        """xadmin的全局配置"""
        site_title = "路飞学城"  # 设置站点标题
        site_footer = "路飞学城有限公司"  # 设置站点的页脚
        menu_style = "accordion"  # 设置菜单折叠
    
    xadmin.site.register(views.CommAdminView, GlobalSettings)
    
  • 相关阅读:
    素数筛的2种方法
    c++含结构体的sort()使用
    构建c++二维vector
    c语言输入单字符避免回车的四种方法
    menset()在c++中的作用
    杭电oj hud1092 1093 活用EOF&n--
    EOF在while(scanf("%d",&n))中的作用
    KMP算法
    图解HTTP(3)
    图解HTTP(2)
  • 原文地址:https://www.cnblogs.com/surpass123/p/13339128.html
Copyright © 2011-2022 走看看