• 笔记:同源政策、跨域资源共享CORS、aiohttp的CORS实现


    2020-03-12:

    读后笔记,原文跳转:

    1、浏览器同源政策及其规避方法,阮一峰,link:http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html

    2、跨域资源共享 CORS 详解,阮一峰,link:https://www.ruanyifeng.com/blog/2016/04/cors.html

    3、aiohttp_cors 库,为aiohttp异步HTTP服务器实现了 跨源资源共享(CORS)支持,link:https://github.com/aio-libs/aiohttp-cors#usage

     

    cookie:Cookie 包含隐私(比如存款总额)。Cookie 往往用来保存用户的登录状态,如果用户没有退出登录,其他网站就可以冒充用户。(后面出一个blog详细学习cookie)

     


     

    一、什么是浏览器同源政策:

    1、同源:协议(http)、域名(www.xxx.com)、端口(8080)都相同,称其为同源。

    2、目的:保护用户信息安全,a网站设置的cookie只能用于同源网站。"同源政策"是必需的,否则 Cookie 可以共享,互联网就毫无安全可言了

    3、同源带来的限制:

      a、Cookie、LocalStorage 和 IndexDB 无法读取;

      b、DOM 无法获得;

      c、AJAX 请求不能发送。(重点来了,这个导致了CORS的出现)

    4、如何规避上述限制:

    (1)、一级域名相同二级域名不同时如何共享cookie? : 浏览器设置 document.domain='xxx.com'; 以共享 Cookie。另外,服务器端设置:Set-Cookie: doman='.xxx.com'; path=/

    (2)iframe窗口window.open方法打开的窗口,它们与父窗口无法通信,原因是两个网页不同源无法拿到对方的DOM,如何解决? :

      a、一级域名相同,二级域名不同,方法同上,设置document.domain

      b、两个网站完全不同源:(iframe跨域问题)

        i、片段识别符(fragment identifier):URL的#号后面的部分。父窗口可以把信息写入子窗口的片段识别符,子窗口通过监听hashchange事件得到通知。反之,子窗口也可以改变父窗口的片段识别符。

        ii、浏览器窗口的window.name 属性:无论是否同源,只要在同一个窗口里,前一个网页设置了这个属性,后一个网页可以读取它。优点是,window.name容量很大,可以放置非常长的字符串;缺点是必须监听子窗口window.name属性的变化,影响网页性能。

        iii、html5新api,跨文档通信API,新增 window.postMessage 方法,父窗口和子窗口都可以通过message事件,监听对方的消息。

    (3)localStorage 的跨域解决:利用window.postMessage 方法,把localStorage将通过消息发送进行通讯。

    (4)ajax跨域请求:

      a、服务器代理:浏览器请求同源服务器,再由后者请求外部服务;

      b、JSONP:网页通过添加一个<script>元素,向服务器请求JSON数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。缺点:只能发GET请求

      c、websocket : WebSocket是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。其中,有一个字段是Origin,表示该请求的请求源(origin),即发自哪个域名。

      d、CORS:下文详述。

    二、什么是跨源资源分享(CORS):

    1、条件:需要浏览器、服务器同时支持,浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

    2、分类:简单请求和非简单请求。区分点,满足的就是简单请求:

    3、简单请求:

      对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段Origin字段用来说明,本次请求来自哪个源(协议 + 域名 + 端口)

      怎么知道请求是否通过?-- 无论如何,浏览器都会返回200,所以状态码不可靠。需要通过回应的头信息没有包含Access-Control-Allow-Origin 判断是否成功,这部分浏览器会自动检查和发起错误。

      -- Origin指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段:

      (1)Access-Control-Allow-Origin;该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。

      (2)Access-Control-Allow-Credentials; (可选,服务器端)表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。另一方面,必须在AJAX请求中打开withCredentials属性。如果要发送Cookie,Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie也无法读取服务器域名下的Cookie。

      (3)Access-Control-Expose-Headers; (可选)CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。

    4、非简单请求:

      (略)

    5、CORS与JSONP的比较:

      JSONP只支持GET请求,CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。

    三、aiohttp-cors 的应用:

      要使用aiohttp_cors,您需要配置应用并在要公开的资源和路由上启用CORS:

    # 1、基本用法:
    
    from aiohttp import web
    import aiohttp_cors
    
    app = web.Application()
    cors = aiohttp_cors.setup(app)  # 返回`aiohttp_cors.CorsConfig`实例
    
    # 要为特定路线使用CORS,您需要添加路由到CORS配置对象并指定其CORS选项。
    resource = cors.add(app.router.add_resource("/hello"))
    route = cors.add(
        resource.add_route("GET", handler), {
            "http://client.example.org": aiohttp_cors.ResourceOptions(
                allow_credentials=True,   # 是否允许证书
                expose_headers=("X-Custom-Server-Header",),  # 该资源将暴露X-Custom-Server-Header 给客户端。
                allow_headers=("X-Requested-With", "Content-Type"),  # 客户端被允许把这些header传给服务端
                max_age=3600,  # 客户端可以将预检请求缓存3600秒
            )
        })
    # 2、资源可以针对不同源可以有不同的规则:
    
    cors.add(route, {
            "*":
                aiohttp_cors.ResourceOptions(allow_credentials=False),
            "http://client.example.org":
                aiohttp_cors.ResourceOptions(allow_credentials=True),
        })
    
    
    #  “*”(除xxx之外所有其他源):允许向其提供内容,但不允许向其提供证书;
    #  with allowed credentials passing only to http://client.example.org.
    # 3、指定默认的启用CORS的资源选项,然后再补充该资源只能被请求的源和请求的方式:
    
    cors = aiohttp_cors.setup(app, defaults={
            # Allow all to read all CORS-enabled resources from
            # http://client.example.org.
            "http://client.example.org": aiohttp_cors.ResourceOptions(),
        })
    
    hello_resource = cors.add(app.router.add_resource("/hello"))
    cors.add(hello_resource.add_route("POST", handler_post))
    cors.add(hello_resource.add_route("PUT", handler_put))
    
    # 也能这么写:
    hello_resource = cors.add(app.router.add_resource("/hello"), {
            "http://client.example.org": aiohttp_cors.ResourceOptions(),
        })
    cors.add(hello_resource.add_route("POST", handler_post))
    cors.add(hello_resource.add_route("PUT", handler_put))
    
    # 还能这么写:
    hello_resource = cors.add(app.router.add_resource("/hello"), {
            "http://client.example.org":
                aiohttp_cors.ResourceOptions(allow_methods=["POST", "PUT"]),
        })
    # 4、例子:允许所有源使用包含所有功能的CORS
    
    cors = aiohttp_cors.setup(app, defaults={
        "*": aiohttp_cors.ResourceOptions(
                allow_credentials=True,
                expose_headers="*",
                allow_headers="*",
            )
    })
    
    # Add all resources to `CorsConfig`.
    resource = cors.add(app.router.add_resource("/hello"))
    cors.add(resource.add_route("GET", handler_get))
    cors.add(resource.add_route("PUT", handler_put))
    cors.add(resource.add_route("POST", handler_put))
    cors.add(resource.add_route("DELETE", handler_delete))
  • 相关阅读:
    读写文件流
    关闭和退出窗口
    有什么问题?
    将aspx页面转换成htm页面
    读取rss聚合文件
    运算符重载实例
    委托
    将 Visual Studio .NET 调试器用于 ASP.NET 应用程序
    输入的字符串进行有规则的清洗
    几个常用的数据库连接字符串
  • 原文地址:https://www.cnblogs.com/marvintang1001/p/12470142.html
Copyright © 2020-2023  润新知