同源策略的解决方案

Posted surpass123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了同源策略的解决方案相关的知识,希望对你有一定的参考价值。

同源策略的解决方案

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)

以上是关于同源策略的解决方案的主要内容,如果未能解决你的问题,请参考以下文章

jFeed 同源策略

同源策略和跨域解决方案 CORS

同源策略和跨域解决方案 CORS

同源策略和跨域解决方案 CORS

同源策略和跨域解决方案 CORS

springBoot 解决前后端分离项目中跨越请求,同源策略