技术讲座:同源策略(SOP)的真正边界与 <script>、<img> 的加载限制
引言
同源策略(Same-Origin Policy,SOP)是Web浏览器的一种安全机制,旨在限制从一个源加载的文档或脚本如何与另一个源的资源进行交互。这一策略防止了恶意文档窃取数据或操作其他源的数据。然而,同源策略的边界并不是绝对的,它对某些类型的资源如 <script> 和 <img> 的加载有一定的例外。本文将深入探讨同源策略的真正边界,并解释为什么它不对 <script> 和 <img> 的加载施加严格的限制。
同源策略概述
定义
同源策略是一种安全策略,它要求从一个源加载的文档或脚本只能访问来自同一源的资源。源由协议(如http、https)、域名和端口组成。
目的
- 防止数据泄露:阻止恶意网站窃取敏感数据。
- 防止操作其他源:防止恶意脚本对其他源的数据进行修改。
限制
- JavaScript:不能读取来自不同源的文档内容。
- CSS:不能读取来自不同源的样式表。
- AJAX:不能发送跨源请求。
<script> 和 <img> 的加载例外
<script> 标签
尽管同源策略限制了JavaScript的执行,但 <script> 标签有一些例外情况:
- 外部JavaScript文件:可以加载并执行来自不同源的JavaScript文件。
- 内联JavaScript:可以包含在HTML文档中,不受同源策略的限制。
示例:加载外部JavaScript文件
<!-- Load an external JavaScript file -->
<script src="https://example.com/script.js"></script>
<img> 标签
与 <script> 类似,<img> 标签也有一些例外:
- 图片资源:可以加载来自不同源的图片资源。
- CSS背景图:可以设置为来自不同源的CSS背景图。
示例:加载外部图片
<!-- Load an external image -->
<img src="https://example.com/image.jpg" alt="Example Image">
同源策略的真正边界
<script> 和 <img> 的边界
尽管 <script> 和 <img> 可以加载来自不同源的资源,但同源策略的边界仍然存在:
- JavaScript执行:即使
<script>可以加载外部文件,但执行脚本时仍然受到同源策略的限制。 - DOM操作:即使
<img>可以加载外部图片,但无法访问或修改来自不同源的DOM元素。
实际应用中的边界
在实际应用中,同源策略的边界可能更加复杂:
- CORS(跨源资源共享):允许服务器指定哪些源可以访问其资源。
- JSONP(JSON with Padding):一种绕过同源策略的技术,但安全性较低。
为什么不限制 <script> 和 <img> 的加载
<script> 标签
- 功能需求:许多Web应用需要加载外部JavaScript库或框架。
- 用户体验:限制
<script>的加载可能会影响用户体验。
<img> 标签
- 视觉需求:Web应用需要加载来自不同源的图片以展示多样性。
- 性能考虑:限制
<img>的加载可能会影响页面加载速度。
总结
同源策略是Web浏览器的一种安全机制,它限制了从一个源加载的文档或脚本如何与另一个源的资源进行交互。尽管 <script> 和 <img> 可以加载来自不同源的资源,但同源策略的边界仍然存在。本文探讨了同源策略的真正边界,并解释了为什么它不对 <script> 和 <img> 的加载施加严格的限制。
附录:工程级代码示例
PHP:验证同源策略
<?php
// 检查请求来源
if (!isset($_SERVER['HTTP_REFERER'])) {
die('Access denied.');
}
// 允许的来源列表
$allowed_domains = [
'https://example.com',
'https://subdomain.example.com'
];
// 检查请求来源是否在允许的列表中
foreach ($allowed_domains as $domain) {
if (strpos($_SERVER['HTTP_REFERER'], $domain) !== false) {
// 请求来源有效
break;
}
}
if (empty($domain)) {
die('Access denied.');
}
?>
Python:使用CORS扩展
# 安装CORS扩展
pip install flask-cors
# Flask应用示例
from flask import Flask, jsonify
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
@app.route('/api/data')
def get_data():
return jsonify({'data': 'This is cross-origin data'})
if __name__ == '__main__':
app.run()
Shell:使用curl发送CORS请求
# 使用curl发送CORS请求
curl -X GET "https://example.com/api/data" -H "Origin: https://subdomain.example.com"
SQL:查询跨源数据
-- 使用SQL查询跨源数据
SELECT * FROM users WHERE source_id = 1;
通过以上示例,我们可以看到同源策略在实际应用中的边界和限制。