HTTP响应头之内容安全策略(CSP)为你的网站保驾护航

2,455 阅读5分钟

小知识,大挑战!本文正在参与「程序员必备小知识」创作活动

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金

前言:本文主要介绍测试环境和正式环境因为nginx服务器配置的CSP(content-security-policy)内容安全策略响应头不一致,导致H5页面在IOS端下加载SKD功能失效的问题复盘

项目背景

我们的一个H5页面,页面域名是https://*.pineapple.com,需要分别内嵌在X appY app里面,X appY app 都有对应的ios端和android端,H5页面分别需要调用X app 或者 Y app提供的sdk,去调用app的功能,如分享功能等

遇到的问题

H5页面在X app里安卓端表现正常,ios端表现不正常,具体表现为在ios机型下,页面引用X app的sdk去调用分享等其他功能失效,安卓则正常。但是H5页面在Y app里安卓端和ios端都表现正常。

导致问题的具体原因

测试环境和正式环境的内容安全策略不一致,正式环境的服务器响应头比测试环境的多了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设置的一些坑,希望能对大家有帮助~如果能获得一个小小的赞作为鼓励会十分感激!!大家也可以多在评论区交流讨论哦

更多文章推荐:

「不再迷茫!看了这篇文章让你上手Vue3.0开发有丝滑般体验」

「三分钟学会使用requestAnimationFrame实现倒计时」

「欢迎在评论区讨论,掘金官方将在掘力星计划活动结束后,在评论区抽送100份掘金周边,抽奖详情见活动文章」