当前位置: 首页 > web >正文

JBoss 项目修复笔记:绕开 iframe 安全问题,JSF 与 Angular 最小代价共存方案

JBoss 项目修复笔记:绕开 iframe 安全问题,JSF 与 Angular 最小代价共存方案

本篇笔记衔接的内容为:JBoss + WildFly 本地开发环境完全指南,里面简单的描述了一下怎么配置 docker,在本地启动一个可以运行的 JBoss 和 WildFly 服务器,接下来就简单描述一下想要解决的问题,以及目前看来比较可靠的解决方法

前言- 背景介绍 & 目标

简单的 recap 一下,我们现在的问题是:

  • 前端还在使用 JSF
    毕竟这是一个老项目了,还在 active support 这个项目的那段时光里,JSF 毕竟还是主流
  • 前端尝试使用 AngularJS
    是 AngularJS,不是 Angular;是 1.x 的版本,不是 2.0+。当时的开发大概是感受到了 JSF 混合 xhtml 的问题——冗长、结构特别复杂、沉重并难以增添新的功能。再搭配上 AngularJS 的确是有 Google 背书,也出现了不少社区支持的 packages,比如说 ng-grid,ng-table 之类,实现起来比春写 JSF 要容易不少
    目前来说我并没有打算深挖 AngularJS 的打算,毕竟我开始做的时候就做 SPA 了,虽然简单的碰过一点 Angular 的内容,也写了点笔记,不过毕竟不是主营
  • 使用 iframe 导入 AngularJS 实现的页面
    这里主要的问题在于,主 xhtml 和使用 iframe 导入的 AngularJS 页面并不分享一个共同的 context,session id 需要通过 URL 明文传到 AngularJS 页面中,最终也是导致了 InfoSec team 给我们好多个 tickets,不能搞定这些安全隐患,那么也就影响现在的生产环境
    当然,这里也有其他的问题,比如说导入非常的散乱,控制器(angular controller)也散的到处都是。不过因为业务相对简单,这种问题还是可以解决的,而且也不是 red flag 🚩,暂时睁一只眼闭一只眼就可以了

鉴于当前的项目也快进入 EOL 了 这种项目提了多少年 EOL 了,什么时候真的 EOL 也不知道,因此当前的目标就是:

  • 最小规模的修改代码,即不动原有的框架结构、文件路径等
    这也可以保证不需要动其他的 xml 文件和 pom 文件,复用原本的 build process
  • 顺利移除 iframe
    这里最大的问题在于 iframe 和主 xhtml 不分享一个 context,那么,如果可以把原本 iframe 运行的内容,放到 xhtml 中,原本的 session 就可以共享,剩下的生命周期流程也可以交给 java 去管理
  • 直接在 xhtml 文件里运行 angular
    这里其实有蛮多的问题的

项目复刻

首先看一下现在的结构:

这里主要修改的就是 webapp/webapp 下面的内容, app 中的是 angular.html 运行的 controller, lib/angular 下面是 angular 官方的 js 和 css 文档, index.xhtml 是 entry point, original.xhtml 是使用 iframe 的 copy,大体结构如此

具体的代码如下:

  • main.controller.js
    这里的代码比较短,主要内容如下:

    (function () {"use strict";angular.module("demoApp", []).controller("MainController", ["$scope",function ($scope) {$scope.title = "🚀 AngularJS 1.3.17 Demo Page";$scope.userInput = "";$scope.items = ["banana", "apple", "mongo"];$scope.addItem = function () {$scope.items.push("new item " + ($scope.items.length + 1));};},]);
    })();
    

    这个写过 Angular 的人多多少少会有点眼熟,Angular 的实现——尽管内部完全不同,但是从实用的角度上来说,还是比较相似的:

    • module 就是新建一个 module,后面的 array 与依赖有关,大体对标的是 NgModule
    • controller 对标的大体就是 controller 中的内容,里面的实现大体对标的事 @Component 中的实现
    • $scope 中可以绑定的就是各种的变量和方法
      整体上可以看出来,AngularJS → Angular 虽然实现方法是完全推翻了,但是核心的实现概念还是一致的。2+比起 1 来说更加的类型安全——感谢 TypeScript 带来的安全感,使用起来也更加的灵活,毕竟:
    • 2+使用的是 TS,而且在编译时进行变量和方法的校验;1 则是使用 JS,运行时动态绑定
    • 2+使用的是 class+decorator 的方法;1 使用的是 controller+scope 的方法
    • 2+默认的是单向绑定,双向绑定需要使用 [(ngModel)];1 默认开启双向绑定,没有什么特别好的选择
    • 2+模板需要 controller 和 view 进行 MVVM 的交流;1 基本在 HTML 中写 template
      我个人感觉,小范围内的项目,1 的写法可能会更方便一些,但是一代码量比较大,或者是陌生的代码,那么 1 找对应的逻辑就比较头疼
      2+的写法虽然相对而言更麻烦一点,不过基于 TS 的检查,以及现代编辑器/IDE 对于 Angular 项目的良好支持,通过查找使用的 reference,和直接点击变量,在 controller 和 view 层来回切换,查找逻辑反而没有那么的困难
  • lib
    这里的内容可以从官方文档里找:https://code.angularjs.org/
    按需下载即可

  • angular.html
    一个简单的 demo,作为 iframe 的导入对象使用,代码如下:

    <!DOCTYPE html>
    <html lang="en" ng-app="demoApp"><head><meta charset="UTF-8" /><title>AngularJS 1.3 Demo</title><link rel="stylesheet" href="lib/angular/angular-csp.css" /><script src="lib/angular/angular.js"></script><script src="app/main.controller.js"></script></head><body ng-controller="MainController"><div style="padding: 2em; font-family: sans-serif;"><h1>{{ title }}</h1><p>🔁 double binding Test:</p><inputtype="text"ng-model="userInput"placeholder="Enter something here..."/><p>You have entered: <strong>{{ userInput }}</strong></p><hr /><p>📋 ng-repeat list rendering:</p><ul><li ng-repeat="item in items track by $index">{{ $index + 1 }}. {{ item }}</li></ul><button ng-click="addItem()">Add more item</button><hr /><p>🎯 ng-if:</p><p ng-if="items.length > 3" style="color: green;">Contrags, you have added more than 3 items!</p></div></body>
    </html>
    

    本质上就是一个比较简单的逻辑,用来确认 AngularJS 的双向绑定、方法、参数等都能在 View 和 Controller 中来回正常交流

  • original.xhtml
    这里就是比较暴力的检验方法了:

    <!DOCTYPE html>
    <htmlxmlns="http://www.w3.org/1999/xhtml"xmlns:h="http://xmlns.jcp.org/jsf/html"
    ><h:head><title>Mock JSF App</title></h:head><h:body><h1>Hello from JSF!</h1><iframesrc="angular/angular.html"style="width: 100%; height: 80vh; border: none"></iframe></h:body>
    </html>
    

    通过导入 iframe 确认 html 文件中的内容可以正常的渲染

最终渲染和现实的结果如下:

WildFly 那边的我就不放了,我已经重新部署了,iframe 的东西是显示不出来了,除非 revert changes

补充代码

这里写了一个小的脚本,因为每次跑完 mvn clean install 都会重新打包 war 和 ear 文件,这也会导致本来的 dorelase 文件被删除,让项目没办法正常部署,还得重新跑一下 docker 的指令,稍微有点麻烦

#!/bin/bashset -eecho "🧨 Step 1: Shutting down any existing containers..."
docker compose downecho "🔧 Step 2: Building jboss-mock module with Maven..."
cd jboss-mock
mvn clean install
cd ..echo "✅ Maven build completed. Artifacts generated in: deployments/"WAR_PATH="./deployments/jboss-mock/webapp-1.0.0.war"
if [ -f "$WAR_PATH" ]; thenecho "📦 Detected .war file. Creating .dodeploy marker to trigger JBoss deployment..."touch "${WAR_PATH}.dodeploy"
elseecho "❌ webapp-1.0.0.war not found! Please check if Maven build succeeded."exit 1
fiecho "🚀 Step 3: Starting container services..."
./start.shecho ""
echo "🎉 Done! You can now visit your app at:"
echo "🔗 http://localhost:8080/webapp-1.0.0/"
echo "🔗 http://localhost:8180/webapp-1.0.0/"

问题定位 & 修复过程

问题定位

其实问题主要出现在这个 <iframe src="angular/angular.html" style="width: 100%; height: 80vh; border: none"></iframe> 这里。前面提到过了,因为 context 没有办法共享的关系,所以在我们实际的生产环境,就需要使用 <iframe src="angular/angular.html?sessionId={someJavaMethod()}" style="width: 100%; height: 80vh; border: none"></iframe> 的方法去调用

明文的 session id 主要有这么几个问题:

  • 容易被截获,也会被 bookmark
  • 暴露于 iframe,可以被 js 文件读取
  • 容易引发 XSS 攻击
  • 无法自动过期

总体来说,我是能理解 InfoSec 为什么会 flag 这个实现的,不过实现起来确实有点头疼……

修复过程

目前来说找到的实现方法是使用放在 panelGroup 里,让 AngularJS 在浏览器中继续执行操作,修改的代码如下:

<!DOCTYPE html>
<htmlxmlns="http://www.w3.org/1999/xhtml"xmlns:h="http://xmlns.jcp.org/jsf/html"
><h:head><title>JSF + AngularJS</title><script src="angular/lib/angular/angular.js"></script><script>angular.module("myApp", []).controller("MainCtrl", function ($scope) {$scope.message = "Hello from Angular 1.3!";$scope.items = ["Item A", "Item B", "Item C"];$scope.addItem = function () {$scope.items.push("Item " + ($scope.items.length + 1));};});</script></h:head><h:body><h:panelGroup layout="block"><!-- JSF will ignore {{ }} as long as it's not within EL context --><div ng-app="myApp" ng-controller="MainCtrl"><h2>{{ message }}</h2><input type="text" ng-model="userInput" /><p>You typed: {{ userInput }}</p><ul><li ng-repeat="item in items">{{ item }}</li></ul><button ng-click="addItem()">Add</button></div></h:panelGroup></h:body>
</html>

因为移除了 iframe,所以不会导入 angular.html 了,渲染结果为:


当然,如果要换成动态导入 JS 文件,也是可以实现的:

<!DOCTYPE html>
<htmlxmlns="http://www.w3.org/1999/xhtml"xmlns:h="http://xmlns.jcp.org/jsf/html"
><h:head><title>JSF + AngularJS</title><script src="angular/lib/angular/angular.js"></script></h:head><h:body><h:panelGroup layout="block"><!-- JSF will ignore {{ }} as long as it's not within EL context --><script src="angular/app/main.controller.js"></script><div ng-app="demoApp" ng-controller="MainController"><h2>{{ message }}</h2><input type="text" ng-model="userInput" /><p>You typed: {{ userInput }}</p><ul><li ng-repeat="item in items">{{ item }}</li></ul><button ng-click="addItem()">Add</button></div></h:panelGroup></h:body>
</html>

效果如下:

⚠️:我 debug 的时候眼瘸, ng-app="demoApp" ng-controller="MainController 没有保证一致,所以 debug 的时候搞了好久都失败,然后重新过了一遍 html 才发现是名字的问题

没有继续尝试的方案

如果还失败,我打算试试 <h:outputText escape="false" />,这个 tag 可以让里面的内容不被转译。目前来说,上面使用 panelGroup 是够了,如果实际运行环境中,用 panelGroup 还不行,那么这个就是我最后的救命稻草了……

失败的尝试方案

这里也简单的说一下一些失败的尝试方案吧……如果有需求也可以试试看,说不定是我漏了什么……

  • 没有移除 iframe,但是移除了 session id
    渲染的页面直接因为没有 session id 拒绝访问

  • 没有用 panelGroup ,直接使用了 HTML tag,但是将 Angular 的所有 attributes 修改为以 data-* 开头的格式
    这里的想法是 xhtml 的检查比较严格,担心可能没办法认出 customized 的 Angular 属性,所以导致直接跳过,因此用 data-* 的方法让 AngularJS 可以识别

    还是没有办法解决 JSF 的转译问题

小结

目前来说这个方法只是延长一下当前项目的生命周期,作为一个 patch 尚可,作为长期的 solution 就有点力有不怠。真正能够解决方法的还是停用 JSF——WildFly/JBoss 官方其实已经不推荐继续用 JSF 了,尽管因为 legacy code 的问题还是继续提供支持,不过也停止了对 JSF3.0 的原生支持

有条件的话还是得往现在主流的 SPA 迁徙,前端御三家选哪个都行……

http://www.xdnf.cn/news/799.html

相关文章:

  • 高防IP能抵御哪些类型的网络攻击?
  • 【Linux】多线程任务模块
  • 【TeamFlow】4.2 Yew库详细介绍
  • 基础版-图书管理系统
  • AOSP Android14 Launcher3——点击桌面图标启动应用动画流程
  • url和http
  • 海外服务器安装Ubuntu 22.04图形界面并配置VNC远程访问指南
  • AI 速读 SpecReason:让思考又快又准!
  • opencv 图像矫正的原理
  • 小刚说C语言刷题——1039 求三个数的最大数
  • PyTorch与TensorFlow模型全方位解析:保存、加载与结构可视化
  • 明心见性与真如三昧
  • CTF web入门之SQL注入使用工具sqlmap
  • 网页下载的m3u8格式文件使用FFmpeg转为MP4
  • C#常用LINQ
  • 快速搭建 Cpolar 内网穿透(Mac 系统)
  • 嵌入式开发板调试方式完全指南:串口/SSH/Telnet及其他方式对比
  • 深度学习框架PyTorch——从入门到精通(3.3)YouTube系列——自动求导基础
  • 【每天一个知识点】主题建模(Topic Modeling)
  • 浙江大学DeepSeek 公开课 第三季 第1期讲座 - 马东方教授 (附PPT下载) by突破信息差
  • 【25软考网工笔记】第三章 局域网(1)CSMA/CD、二进制指数退避算法、最小帧长计算
  • 高品质性价比之王-特伦斯便携钢琴V10
  • 海外版高端Apple科技汽车共享投资理财系统
  • Spark-SQL编程
  • 【第十六届 蓝桥杯 省 C/Python A/Java C 登山】题解
  • 《Java工程师面试核心突破》专栏简介
  • Uniapp 自定义TabBar + 动态菜单实现教程(Vuex状态管理详解)
  • Docker如何更换镜像源提高拉取速度
  • 【Easylive】为什么需要手动转换 feign.Response 到 HttpServletResponse
  • Itext进行PDF的编辑开发