0%

跨域

同源策略

同源策略的定义

同源策略要求,只有当两个 URL 的协议、域名和端口都相同时,才能互相访问其资源。具体来说,同源策略检查以下三个部分是否相同:

  1. 协议(如 httphttps
  2. 域名(如 example.comsub.example.com
  3. 端口(如 80443

示例

  • http://example.com/page1http://example.com/page2 是同源的。
  • http://example.comhttps://example.com 不是同源的(协议不同)。
  • http://example.comhttp://api.example.com 不是同源的(域名不同)。
  • http://example.com:80http://example.com:8080 不是同源的(端口不同)。

同源策略的具体限制

同源策略限制了以下几种跨域访问:

  1. DOM 访问:一个源的脚本不能访问或操作另一个源的 DOM。
  2. Cookie 访问:一个源的脚本不能读取或写入另一个源的 Cookie。
  3. AJAX 请求:一个源的脚本不能向另一个源发起 AJAX 请求,除非目标源允许(通过 CORS)。
  4. LocalStorage 和 SessionStorage 访问:一个源的脚本不能访问另一个源的本地存储数据。

同源策略的作用

同源策略主要用于以下几种情况:

  1. Cookie:防止一个网站读取另一个网站的 Cookie。
  2. DOM:防止一个网站操作或读取另一个网站的 DOM。
  3. AJAX 请求:防止一个网站通过 AJAX 请求读取另一个网站的数据。

同源策略的例外

虽然同源策略是默认的安全机制,但有一些方法可以绕过或放宽同源策略,以实现跨域资源共享:

  1. CORS(跨域资源共享):服务器通过设置特定的 HTTP 头,允许跨域请求。
  2. JSONP:通过 <script> 标签的 src 属性来请求跨域资源,因为 <script> 标签不受同源策略限制。
  3. PostMessage:使用 window.postMessage 方法在不同源的窗口之间进行安全通信。
  4. 代理服务器:通过服务器端代理请求目标资源,然后将结果返回给客户端。

JSONP 示例

  • 通过 <script> 标签的 src 属性来请求跨域资源,因为 <script> 标签不受同源策略限制。
  • 只能用于 GET 请求。

服务器端

1
2
3
4
5
6
7
8
9
10
11
12
const express = require('express');
const app = express();

app.get('/data', (req, res) => {
const callback = req.query.callback;
const data = { message: 'Hello, JSONP!' };
res.send(`${callback}(${JSON.stringify(data)})`);
});

app.listen(3000, () => {
console.log('Server is running on port 3000');
});

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html>
<head>
<title>JSONP Example</title>
<script>
function handleResponse(data) {
console.log(data.message);
}
</script>
</head>
<body>
<script src="http://localhost:3000/data?callback=handleResponse"></script>
</body>
</html>

CORS(跨域资源共享)

  • 服务器在响应头中添加特定的 HTTP 头,允许跨域请求。
  • 支持 GET、POST、PUT、DELETE 等多种 HTTP 方法。

服务器端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const express = require('express');
const app = express();

app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
});

app.get('/data', (req, res) => {
res.json({ message: 'Hello, CORS!' });
});

app.listen(3000, () => {
console.log('Server is running on port 3000');
});

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html>
<head>
<title>CORS Example</title>
<script>
fetch("http://localhost:3000/data")
.then((response) => response.json())
.then((data) => console.log(data.message))
.catch((error) => console.error("Error:", error));
</script>
</head>
<body></body>
</html>