我是打算在php网站中的一个HTML文件使用iframe标签调用django网站时遇到的问题,这句话说得好像有点繁琐,就是使用iframe时遇到的问题。查了很多相关资料,又说php网站的,有说html中没有设置,有说apache中需要配置,我全部尝试一遍之后都没有解决,后知后觉,发现django中间件问题。先了解一下背景知识。
1.同源策略
什么叫同源?
URL由协议、域名、端口和路径组成,如果两个URL的协议、域名和端口相同,则表示他们同源。相反,只要协议,域名,端口有任何一个的不同,就被当作是跨域。
e.g. 对于http://store.company.com/dir/page.html进行同源检测:
URL | 结果 | 原因 |
---|---|---|
http://store.company.com/dir2/other.html | 成功 | 仅路径不同 |
http://store.company.com/dir/inner/another.html | 成功 | 仅路径不同 |
https://store.company.com/secure.html | 失败 | 协议不同 |
http://store.company.com:81/dir/etc.html | 失败 | 端口不同 |
http://news.company.com/dir/other.html | 失败 | 主机名不同 |
同源策略 Same-Origin-Policy(SOP)
浏览器采用同源策略,禁止页面加载或执行与自身来源不同的域的任何脚本。换句话说浏览器禁止的是来自不同源的"document"或脚本,对当前"document"读取或设置某些属性。
情景:
比如一个恶意网站的页面通过iframe嵌入了银行的登录页面(二者不同源),如果没有同源限制,恶意网页上的javascript脚本就可以在用户登录银行的时候获取用户名和密码。
浏览器中有哪些不受同源限制呢?
<script>、<img>、<iframe>、<link>这些包含 src 属性的标签可以加载跨域资源。但浏览器限制了JavaScript的权限使其不能读、写加载的内容。
2.跨域
跨域是指从一个域的网页去请求另一个域的资源。比如从http://www.baidu.com/ 页面去请求 http://www.google.com 的资源。
2.跨域
跨域是指从一个域的网页去请求另一个域的资源。比如从http://www.baidu.com/ 页面去请求 http://www.google.com 的资源。
点击劫持保护
点击劫持中间件和装饰器提供了简捷易用的,对点击劫持的保护。这种攻击在恶意站点诱导用户点击另一个站点的被覆盖元素时出现,另一个站点已经加载到了隐藏的frame
或iframe
中。
点击劫持的示例
假设一个在线商店拥有一个页面,已登录的用户可以点击“现在购买”来购买一个商品。用户为了方便,可以选择一直保持商店的登录状态。一个攻击者的站点可能在他们自己的页面上会创建一个“我喜欢Ponies”的按钮,并且在一个透明的iframe
中加载商店的页面,把“现在购买”的按钮隐藏起来覆盖在“我喜欢Ponies”上。如果用户访问了攻击者的站点,点击“我喜欢Ponies”按钮会触发对“现在购买”按钮的无意识的点击,不知不觉中购买了商品。
点击劫持的防御
现代浏览器遵循X-Frame-Options协议头,它表明一个资源是否允许加载到frame
或者iframe
中。如果响应包含值为SAMEORIGIN
的协议头,浏览器会在frame
中只加载同源请求的的资源。如果协议头设置为DENY
,浏览器会在加载frame
时屏蔽所有资源,无论请求来自于哪个站点。
Django提供了一些简单的方法来在你站点的响应中包含这个协议头:
- 一个简单的中间件,在所有响应中设置协议头。
- 一系列的视图装饰器,可以用于覆盖中间件,或者只用于设置指定视图的协议头。
如何使用
为所有响应设置X-Frame-Options
要为你站点中所有的响应设置相同的X-Frame-Options
值,将'django.middleware.clickjacking.XFrameOptionsMiddleware'
设置为 MIDDLEWARE_CLASSES
:
MIDDLEWARE_CLASSES = (
...
'django.middleware.clickjacking.XFrameOptionsMiddleware',
...
)
这个中间件可以在startproject生成的设置文件中开启。
通常,这个中间件会为任何开放的HttpResponse
设置X-Frame-Options
协议头为SAMEORIGIN
。如果你想用 DENY
来替代它,要设置X_FRAME_OPTIONS
:
X_FRAME_OPTIONS = 'DENY'
使用这个中间件时可能会有一些视图,你并不想为它设置X-Frame-Options
协议头。对于这些情况,你可以使用一个视图装饰器来告诉中间件不要设置协议头:
from django.http import HttpResponse
from django.views.decorators.clickjacking import xframe_options_exempt
@xframe_options_exempt
def ok_to_load_in_a_frame(request):
return HttpResponse("This page is safe to load in a frame on any site.")
为每个视图设置 X-Frame-Options
Django提供了以下装饰器来为每个基础视图设置X-Frame-Options
协议头。
from django.http import HttpResponse
from django.views.decorators.clickjacking import xframe_options_deny
from django.views.decorators.clickjacking import xframe_options_sameorigin
@xframe_options_deny
def view_one(request):
return HttpResponse("I won't display in any frame!")
@xframe_options_sameorigin
def view_two(request):
return HttpResponse("Display in a frame if it's from the same origin as me.")
注意你可以在中间件的连接中使用装饰器。使用装饰器来覆盖中间件。
限制
X-Frame-Options
协议头只在现代浏览器中保护点击劫持。老式的浏览器会忽视这个协议头,并且需要 其它点击劫持防范技巧。
支持 X-Frame-Options 的浏览器
- Internet Explorer 8+
- Firefox 3.6.9+
- Opera 10.5+
- Safari 4+
- Chrome 4.1+
以上是django能否被iframe使用的情况,如果你想能被其他网站直接使用,就将django网站的setting文件中的
'django.middleware.clickjacking.XFrameOptionsMiddleware',
屏蔽掉就好
我的问题已经解决。但是网上仍有很多解释,我感觉碰到的原因可能不同,我这次也记录一下:
在apache 中配置:
先讲一下 X-Frame-Options的作用,赋值有如下三种: (1)DENY:不能被嵌入到任何iframe或frame中。 (2)SAMEORIGIN:页面只能被本站页面嵌入到iframe或者frame中。 (3)ALLOW-FROM uri:只能被嵌入到指定域名的框架中。
防止某些重要网页被其他网站框架导入,可以给页面增加X-Frame-Options响应头,这样浏览器会依据X-Frame-Options的值来控制iframe框架的页面是否允许加载显示出来,IE下的效果如下(此内容无法再框架中显示。为了帮助保护在此网站中输入的信息安全,此内容的发行者不允许在框架中显示该信息),其他非IE核心浏览器会显示空白内容。
动态页添加X-Frame-Options响应头代码在此详细附上设置过程
1>开启Apache的扩展headers_module,
2>在Apache配置文件的空白行加上一下代码:
Header always append X-Frame-Options SAMEORIGIN
完成以上部分,重启Apache服务即可审查页面出现如下代码表示设置成功
参考:https://www.html.cn/archives/5141