Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

如何理解same-origin policy? #144

Open
FrankKai opened this issue Apr 27, 2019 · 4 comments
Open

如何理解same-origin policy? #144

FrankKai opened this issue Apr 27, 2019 · 4 comments

Comments

@FrankKai
Copy link
Owner

主要参考文档:https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#Original_Document_Information

@FrankKai
Copy link
Owner Author

FrankKai commented Apr 28, 2019

same-origin policy是一个严格的安全策略,它可以用来限制document或者script如何从一个origin加载,然后与另一个origin的资源进行交互。隔离了潜在危险的恶意documents,减少网站被攻击的次数。

origin的定义

如果两个URL协议相同、端口相同、主机也相同,那么它们是same origin。我们看到的一般是一下两种形式:

  • "scheme/host/port tuple"
  • "tuple"

注释:tuple是一组数据的集合,可以是表单,也可以是2个,3个,4个参数等等。

http://store.company.com/dir/page.html为例:

URL Outcome Reason
http://store.company.com/dir2/other.html Same origin Only the path differs
http://store.company.com/dir/inner/another.html Same origin Only the path differs
https://store.company.com/page.html Failure Different protocol
http://store.company.com:81/dir/page.html Failure Different port (http:// is port 80 by default)
http://news.company.com/dir/page.html Failure Different host

最后http://news.company.com/dir/page.html的不一定,如果在hosts文件中进行映射,例如下面这样,那么它们也是同源:
/etc/hosts

192.168.0.23 news.company.com store.company.com:

因为此时它们的host是相同的。

继承origins

  • about:blank it does nothing more than display a blank page.
  • 通过window.open()打开的新窗口,如果此弹出窗口还包含JavaScript,则该脚本将继承与创建它的脚本相同的源。

源的更改

一般来说,更多的是调用其getter。

const forbiddenDomain = "996.icu";
if(document.domain === forbiddenDomain){
    // Scripts may close only the windows that were opened by it.
    // 仅仅可以关闭由当前window打开的窗口.
    window.close();
}

调用setter,可以将端口更改为null,可以进行端口不同跨域通信。

document.domain = document.domain;

@FrankKai
Copy link
Owner Author

FrankKai commented Apr 28, 2019

跨域网络权限

同源策略主要控制着2个不同源的交互,例如当你使用XMLHttpRequest或者<img>标签。这个交互一般分为3类:

  • 跨域 ,允许。例如链接,重定向以及表单提交。一些需要HTTP预检请求,预检请求一般是OPTIONS。
  • 跨域,允许。(这很重要,因为时时刻刻发生,而身为前端的你却不知道。)
  • 跨域,不允许,但是经常被嵌权限泄露。例如,你可以读取嵌入图像的尺寸,嵌入脚本的动作,或者其他嵌入资源的能力。

这里有一些跨域的一些资源类型:

  • <script src="…"></script>
  • <link rel="stylesheet" href="…"> 跨域CSS的Content-Type请求头必须正确
  • 通过<img>显示的资源
  • <video>``<audio>请求的视频,音频
  • 通过<object>``<embed>``<applet>嵌入的插件
  • 通过@font-face获取到的字体,一些浏览器允许跨域fonts,其他的需要同源。
  • <frame><iframe>标签中的内容。可以通过X-Frame-Options请求头阻止跨域frame。

拓展:
1.X-Frame-Options是什么?
是一个响应头,用来控制浏览器是否渲染<frame><iframe><embed><object>。可以用来避免clickjacking攻击。

X-Frame-Options: deny
X-Frame-Options: sameorigin
X-Frame-Options: allow-from https://example.com/

nginx配置:add_header X-Frame-Options sameorigin always;
2.什么是clickjacking 攻击?
中文名叫做点击劫持。

Clickjacking(通常被称为用户界面补救攻击),这是一个恶意技术,因为它会触发用户本不会去进行的一些点击,所以会潜在泄露保密信息的危险或者是会被恶意操控计算机。

在Web浏览器中,clickjacking是一个浏览器安全问题,这是很多浏览器和平台都存在的漏洞。Clickjacking可以在浏览器意外的应用程序中发生。

Clickjack采用嵌入式代码或脚本的形式,可以在用户不知情的情况下执行,例如单击看似执行其他功能的按钮。

那么如何避免Clickjacking呢?
凭借我有限的2年前端开发经验,可以通过事件对象events的isTrusted属性进行安全控制。可以查看:一些想不到的前端安全知识点

如何开启跨域权限

CORS,关于CORS,需要前后端的通力协作。

前端配置CORS

axios配置项

withCredentials: true
nodejs koa2 配置CORS

引用依赖koa-cors

var cors = require('koa-cors');
app.use(cors());
java spring-boot 配置CORS
package com.arya.spring.vue.aryaspringvuebe;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@SpringBootApplication
public class AryaSpringVueBeApplication {

	public static void main(String[] args) {
		SpringApplication.run(AryaSpringVueBeApplication.class, args);
	}
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                // 映射项目路由,允许/spring/vue下的所有接口跨域。注意**才是代表所有路由,否则*仅仅是类似/spring/vue/update一级路由,不支持/spring/vue/update?id=1。
                registry.addMapping("/spring/vue/**")
                        // 设置Access-Control-Allow-Method: "GET", "POST", "PUT", "DELETE"
                        .allowedMethods("GET", "POST", "PUT", "DELETE")
                        // 设置Access-Control-Allow-Origin:http://localhost:3000,指定可访问源。注意PUT和DELETE引起的OPTIONS预检请求需要指定源,不可设置为*。
                        .allowedOrigins("http://localhost:3000")
                        // 设置Access-Control-Allow-Headers: content-type。
                        .allowedHeaders("Content-Type")
                        // 设置Access-Control-Max-Age: 3600。注意这里是Long类型的
                        .maxAge(3600L)
                        // 设置响应Access-Control-Allow-Credentials: true。
                        .allowCredentials(true);
            }
        };
    }
}

如何阻止跨域权限

  • 为了阻止跨域写,检查请求头中的token-也就是CSRF token。必须阻止需要CSRF token的跨域读。
  • 为了阻止跨域读,确保禁止嵌入。可以通过X-Frame-Options阻止嵌入内容。
  • 为了阻止跨域嵌,尽量确保资源是上述的一种。资源不是入口点可以通过CSRF token阻止嵌入。

@FrankKai
Copy link
Owner Author

FrankKai commented Apr 28, 2019

跨域脚本API权限

iframe.contentWindow, window.parent, window.open, and window.opener这些API,允许文档直接互相调用。
当两个文档不在同源的情况下,会对window和location的API进行一些限制,就像下面两个部分描述的一样。

为了在不同的document间进行通信,需要用到window.postMessage。可以参考:什么是Web Workers?

Window

下面的这些方法是允许 cross-origin 的。

window.blur
window.close
window.focus
window.postMessage
Attributes  权限
window.closed Read only.
window.frames Read only.
window.length Read only.
window.location Read/Write.
window.opener Read only.
window.parent Read only.
window.self Read only.
window.top Read only.
window.window Read only.

Location

方法location.replace
属性URLUtils.href 只写

@FrankKai
Copy link
Owner Author

跨域数据存储权限

localStorage和IndexedDB也会有源的区分。每个源都有自己独立的storage,而且一个源下的js,不能读写另一个origin下的数据。

  • Cookies会有origin的划分
  • 页面可以为自己的domain设置cookie,也可以为父domain设置cookie,只要父域不是一个公共的后缀。
  • ff和chrome用https://publicsuffix.org/去验证父domain是不是公共后缀;ie用自己的方法。
  • 无论使用哪种协议(HTTP / HTTPS)或端口,浏览器都会为给定域(包括任何子域)提供cookie。
  • 当你设置cookie的时候,你可以使用Domain,Path,Secure和Http-Onlyflag进行控制。
  • 在你读cookie的时候,你看不到它从哪里设置的。看到的任何cookie都可能使用不安全的连接。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant