内容安全策略(content-security-policy)为你的网站保驾护航
前言:本文主要介绍测试环境和正式环境因为nginx服务器配置的CSP(content-security-policy)内容安全策略响应头不一致,导致H5页面在IOS端下加载SKD功能失效的问题复盘
项目背景
我们的一个H5页面,页面域名是https://*.pineapple.com
,需要分别内嵌在X app
和 Y app
里面,X app
和 Y app
都有对应的ios端和android端,H5页面分别需要调用X app
或者 Y app
提供的sdk,去调用app的功能,如分享功能等
遇到的问题
安卓表现正常,ios下表现不正常,具体表现为在ios机型下,页面引用X APP的sdk去调用分享等其他功能失效,安卓则正常
导致问题的具体原因
测试环境和正式环境的内容安全策略不一致,正式环境的服务器响应头比测试环境的多了content-security-policy,导致H5页面在X app
内加载SDK成功后,但通过iframe src触发伪协议的请求被csp拦截了,从而引发分享等功能失效,因而问题没在测试环节提前暴露出来。
原正式环境配置的响应头:
Content-Security-Policy: script-src <https://*.baidu.com><https://*.pineapple.com> 'unsafe-inline' 'unsafe-eval'; frame-src <https://*.pineapple.com><http://*.pineapple.com> webcompt:; report-uri <https://一个废弃的地址>复制代码
什么是Content-Security-Policy
content-security-policy(内容安全策略)主要是定义了当前哪些资源可以被页面加载,也可以指定控制浏览器加载iframe的资源范围。CSP的作用主要是为了减小和报告XSS攻击。
解决方案
定位csp内容拦截了那部分内容然后进行修改,以及测试环境也添加上csp,让问题及时暴露,以免上线前才匆忙暴露问题。
把配置里的 frame-src 和 report-uri去掉了就可以了,因为report-uri 里的这个地址没再维护了,因此 frame-src设置有问题
后面线上改成响应头是:
Content-Security-Policy: script-src <https://*.pineapple.com> 'unsafe-inline' 'unsafe-eval';复制代码
怎样定位到问题的
刚刚开始真的是超级难定位问题的,因为走代理的时候没经过配置的服务器,因而代理的时候又可以正常成功,像极了双缝干涉实验
一样,是否观察影响了结果。此时其实可以考虑到是服务器的原因
1.猜测是否在ios机型下,页面加载sdk失效
原以为是三端sdk加载失败,实际加载成功了,只是里面的请求(native和h5交互的请求)被CSP拦截了
2.配置了代理正常,不配置代理就异常
因为导致这个问题是由于经过服务器返回导致的,配置了代理走的是本地的,没有走配置的nginx服务器,因此配置了代理就可以了,此时应该就思考服务器的影响了
3.测试环境和正式环境的区别
经定位发现正式环境服务器配置多了个CSP,附以下whistler配置返回头的教程
如何调试CSP
3.1 在rules配置:
/<https://*.pineapple.com/> resHeaders://{cspHeader}复制代码
3.2 cspHeader配置:
content-security-policy: script-src <https://*.pineapple.com/> 'unsafe-inline' 'unsafe-eval'复制代码
3.3 配置手机代理,即可进行调试,从而修改策略内容定位问题。
导致该问题的原理分析
经过定位排查是frame-src的配置导致的,那为什么ios下配置frame-src失效,安卓却是正常,这就要说要到Hybird APP之native和原生h5的交互原理,经查阅资料得知
1.ios是原生h5通过调用js bridge,js bridge内创建一个iframe,然后通过修改iframe的src为提前定义好的伪协议,去触发scheme,或者其他native自带方式。
2.安卓可以不用修改iframe的src方法去触发scheme,而是调用window.prompt(uri, '')的方式去触发scheme,或者其他native自带的原生交互方式(注意原生交互方式对ios和android低版本不兼容)。
综上所述,js bridge是分别针对ios和安卓的系统调用不同方法进行捕获scheme的触发。
为了验证上面的原理,我搜了下X app
下的bridge的源码发现确实是有创建iframe的一步。但是Y app
源码是没有创建iframe的一步,是使用native自带原生的交互方式。就可以大致解析Y app
为什么可以正常,加载X app
的sdk后调用里面的功能失效。
最后
以上是我在内嵌页面遇CSP设置的一些坑,希望能对大家有帮助~如果能获得一个小小的赞作为鼓励会十分感激!!大家也可以多在评论区交流讨论哦
作者:一只凤梨
链接:https://juejin.cn/post/7022869337035767815