Cyber Security Visualisation
A 3D counterpart to a dashboard
Bricksol was approached by a client looking to integrate 3D visualization with their upcoming cyber security dashboard.
- The 3D visualization needs to run on all web-compatible devices.
- The 3D view needs to be high fidelity and be quick to respond.
- The 3D view must reflect the dashboard.
- The 3D view must show the actual locations where the cybersec tools are deployed
A demo
An tech demo shows the bones of the delivered product.
Stick around for a better demo later on.
Planning
With responsiveness and dynamism required, threeJS would be a natural choice. But the client's requirement of high fidelity and client compatibility directed us towards using Unreal Engine and streaming it to the webpage.
Why stream Unreal Engine?
- High fidelity is a no brainer. ThreeJS on a browser cannot come close to a renderer running directly on the OS (high hopes for webgpu).
- Since the client needs "the actual locations where the cybersec tools are deployed", it makes sense to use a GeoVis tool. By streaming the video from a dedicated renderer, we ensure that the GeoVis data is cached which decreases load times.
Implementation
Renderer
It starts simple, the rendering Unreal binary needs to load Cesium at the right co-ordinates. Once loaded, it needs to provide controls for navigation, and representations of the cybersec components
Placement Algorithm
At first, the requirements dictated that the objects would be placed by themselves. For this reason, I worked on a grid system similar to Project Gaslight. However, this was scrapped for a system that gives the creators freedom to pick a procedurally generated level or a hand-crafted level. As the product itself was a demo, we settled on a hand-crafted approach with slots left to include procedural levels if necessary.
Sending data from the webpage
The webpage, at client side, needs to talk to a running Unreal binary. It needs to:
- Wait till the binary is started
- Tell the binary which level should be loaded
- Wait till the right level is loaded to send the component data
The communication was done over the PixelStream API. I set architecture guides in place for future developers to add to the communication system.
Then, a component was needed that read data from the page's state and sent it over to the renderer. I created such a component. Essentially, all sensitive data is loaded by the client. If the client is authenticated for the data, then so is the renderer. Since PixelStream message API is TCP, the messages cannot be intercepted.
Using data from the webpage
The binary starts in a "dormant" state with no level loaded. Once a webpage makes contact with it, it outputs data about the loaded level (if one was previously loaded). It receives data over the PixelStream API to then load the right level, or the data of the network if the right level is loaded.
In the case of our hand-crafted level, it then needs to link the data with the right actors. This includes the network components, the connection between them, master and subordinates, and the health of these connections. It also provides UI to quickly bring each component into focus.
This would be a nightmare to test in a situation where we only had the website, so I put debugging constructs in place for easy iterative testing. These can be seen here:
Got a microphone just after this project
Displaying the links
In the hand-crafted levels, the links are generated with Geometry Script. In the tech demo above, you can see some approaches I later implemented for links that bend and curve. However, they cannot be generated at runtime. Instead, I pool a bunch of these links at engine start, place them according to the sent data, and add offsets to the material instance to make them appear uniform. Since it renders on a powerful computer not on the client, the overhead does not affect it that much.
Then, to show connection health, the lines change speed, color, brightness and stripe width.
A wrinkle appeared later, as the lines looked very static and tacked-on. They did not react to the lighting at all and looked extremely two-dimensional. However, changing their surface type would break other features, such as the lines drawing on top of everything else. To fix this, I used the same tricks as Ben Cloward uses in his Fantasy Health Meter series to fake lighting around the rims of the links. This is easily visible in the tech demo above. With this improved shader, the links look rounded and responsive to lighting.
Deployment
Initially slated to deploy on a local server, with an intermediary matchmaker system, it was later scrapped in favor of hosting the renderer on ArcaneMirage. This took away a lot of the headache of programming for network issues, with sacrifice of initial load times.
What I would have done differently
Satisfying both requirements between running on a webpage and being high-fidelity was a major point. Knowing the final scale of the project, I would have encouraged the use of ThreeJS for the webpage integrated version, and a separate binary that runs on the client for the high fidelity version. However, the result was adequate for the client's pitch.