知识库

记录点点滴滴

jupyterhub cross origin [解决跨域问题]

前言

这几天想做一个通过jupyter api实现的自制前端UI,而访问api的方式自然选择了使用ajax。本以为这会是一个很简答的任务,但是实际操作起来,发现利用ajax访问jupyter api时存在跨域的问题,由于jupyterhub运行后,开放在默认的8000端口上,而自制的页面一般在80/443端口,因此要自制这个页面需要先解决跨域的问题。

表现症状

在请求相关接口时,控制台中提示

Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

简单的翻译一下就是 在被请求的资源上没有被允许的非同源origin

同时也可以在network中看到

《jupyterhub cross origin [解决跨域问题]》

方法为OPTIONS,表示在试探服务器是否能够相应这个api,而Response Headers返回给浏览器,告知服务端相关的情况,而这个时候在这个响应头中没有Access-Control-Allow-Origin一项,浏览器便默认不可进行跨域访问,即非同源的请求在浏览器一端就会被拦截。而如果响应头中有Access-Control-Allow-Origin=“*”,表示服务器可以接受来自任何源的请求,这个时候浏览器就不会自动拦截请求了。因此,针对jupyterhub应用场景(既要post又要get),在跨域解决方案上,我选择了CORS。

解决原理

CORS是一种可以让你实现跨站点请求并同时阻止恶意js的请求,它会在你发送下面几种HTTP请求时触发:

– 不同的域名 (比如在网站 example.com 请求 api.com)

– 不同的子域名 (比如在网站 example.com 请求 api.example.com)

– 不同的端口 (比如在网站 example.com 请求 example.com:3001)

– 不同协议 (比如在网站 https://example.com 请求 http://example.com)

这个机制阻止攻击者在一些网站上放置js脚本(比如通过Googls Ads展示的广告)发起一个AJAX请求访问www.yourbank.com,假设你刚好登陆过这个网站,就可能使用你的验证信息发起一笔转账。

如果你的浏览器发起一个“非简单”请求(比如这个请求里包含了cookies,或者Content-typeapplication/x-ww-form-urlencodedmultipart/form-data 或者 text-plain)一个叫做预检查的机制会发送一个OPTIONS请求到服务器。如果服务器没有返回带有特殊头部的数据,简单请求GET或者POST请求仍然会发送,服务器的数据也会返回,但是浏览器会阻止Javascript获取这次请求。

如果明确的需要在一个请求里添加cookies,自定义头部信息或则其他特性,这将不在是一个简单请求,并且服务器没有适当的返回,这次请求讲不会发送。就是复杂请求时,如果OPTIONS的请求,服务器没有做出适当的返回,后面真实的请求将不会发送。

解决方案

本方案针对jupyterhub,其他库大同小异

方案一(原创):

用命令找到jupyterhub/handlers/base.py,188行处set_default_headers函数增加三行内容

用命令找到jupyterhub/singleuser.py,593行附近

用命令找到jupyter_notebook_config.py,48行附近

最后重启服务就可以看到效果了

灵感来源:base.py往往是被其他文件集成,用于配置一些基本的相应等形式,因此对于跨域问题,可以优先去找base.py,并修改其内容,但是当修改完成之后,用下面的测试程序测试发现第一个/hub/api通过了,但是第二个/user/xukeqin/api则失败了,从请求的反馈来看,这两者api存在一个典型的区别是,前者是全局的api,而后者是针对用户的api,因此其配置文件可能另存在其他文件中,通过spawner创建进程的形式产生该api接口,所以我在这个库文件中搜索相应的关键字,渴望找到该单用户进程的人口,最终经过筛选,锁定在singeruser.py中

方案2

用命令找到jupyterhub_config.py,增加以下内容

juoyterhub的配置和jupyter notebook的不太一样,后者修改完配置文件后,能够直接生效,但是jupyterhub经过测试,需要添加命令行参数才可以手动生效,命令如下:

 

最终测试

如果最后没有任何提示请求失败,就表示跨域成功咯!

解决iframe安全问题

在jupyterhub_config.py中设置

其中host_ip为主机号,port为端口号

点赞

发表评论

邮箱地址不会被公开。 必填项已用*标注