Is there a way to not allow the user to publicly download the 3d model and texture files that i'm showing?

I’m building a marketplace for 3d assets and I need to have a 3d viewer that allows the user to view the 3d models before downloading, but I need the files to still be protected to where they can’t be downloaded.

Hello atylerrice,

I am glad you are asking this question, because it is certainly the up most important security question pertinent to ALL webGL (THREE.js) applications.

From what I have seen thus far almost nobody (standards, libs, frameworks) provides a solution to such problematic, because it is a complex issue that span into another category of expertise rarely found in the domain of computer graphics and which is (most of the time) done last in computer development: Security.

There is certainly multiple aproach that would solve the problem temporarely, but to do it right once and for all, it takes a strong fundation that affects everything from the ground up: processes, code, UIs, scripts, object files… You wish to protect the 3d models, but you may also want to protect your scripts, so hackers would not be able to clone your site easily or find an exploit to take control, or bypass game logic, etc…

The only long term approach to resolve this problem is to apply a series of web security best practices :

  • multiple encryption levels
  • server side token verification
  • multiple proprietary/private steps

Note: there is a tradeoff between performance & security strength when applying multiple steps specific to each case scenario.

Yes, this solution takes a lot of man hours and another kind of expertise in order to do it right. Plus, every security solution is not 100% bulletproof neither, but the time spend to crack such approach would be so large that it makes no sense to apply energy cracking it.

If you need a solution right away and don’t want to spent time in security dev., I know one company providing such security service via a middleware: http://multivers3D.fr

Hope this info will help you move further. I know, it may not be the answer you were expecting, yet again, it is a complex problem touching everyone, thank you for asking!

That’s not possible, except for textures you could watermark, or for example merged watermark geometries. Encryption doesn’t matter, once it’s decoded you can grab the buffers.

You can only make it harder by using a custom format, and watermark things, serve lower res previews, or even just no 3D preview at all, like a 360 turntable.

1 Like

I challenge anyone to get this model into its json format (even from the buffer):

https://multivers3d.fr/constructor/templates/scripts/crypt/components/fsdfsdfsjghfffsdfghdfghdfgdgsdfdsfsfdsdfsdfsdfdfdfsd.js

Note: The model is in the main site intro

The format doesn’t matter, he wants to preview them, once you display it the buffers are exposed. One could even extract it from outside chrome, and automate this process with a tool.

@Fyrestar, let’s not change the subject, the question is “there a way to not allow the user to publicly download the 3d model and texture files

The solution is to encrypt the object files and put a watermark on the texture files as @anon13924900 suggested.

The buffer security issue is another problem that deserves its own thread.

I am lekxi, discourse doesn’t react to github changes.

The point is, he wants to preview all of them so it is about the buffers. One tool and you could automate to download all models through WebGL. Encrypting the files only would be useful when the preview isn’t the actual real model in WebGL. Hidden watermark geometries would at least make it hard to remove them.

Here is an approach to the buffer issue:

For the merged geometry, that’s what i suggested but only for this preview scenario, it would procedurally embed watermark symbols inside the mesh so

  • The polycount would probably be an issue in productive usage

  • It would be a lot work to remove all of it

  • Some might not even notice it (they are scaled to precision limit)

For the indices offset or something like this i don’t think we can do this with WebGL (indices can’t get altered on the gpu), as it requires a fully decoded and exposed state.

For real world applocations i don’t see any full protection method, anyone who wants it will get it. My opinion, and a lot other you will find around this topic is: don’t waste your time with such protection things that won’t give much protection at all.

I use a custom asset format which comes fully binary in a chunked stream, requested from a repository api which requires a account, that’s protection enough for me, as it’s no open source. It’s worth making it harder and proprietary, but that’s all. In the end one could always grab it directly from the GPU.

What he want’s to do is a different case, the watermark method for both, or preview as image / turntable would be reasonable, but not in a real application. I would’nt count on anything else, as such a market place would worth the effort to develop a tool to automate the extraction. Other marketplaces also don’t show 3D previews (such as turbosquid) and there’s a good reason for it.

My suggestion, just allow the authors to preview them, choose a pose for a image, maybe generate a turntable stripe, but don’t serve 3D previews in the market. The authors probably won’t trust it, and you can ensure to serve constant traffic for the previews, some might have several textures or a large geometry.

2 Likes

@Fyrestar @anon13924900, who ever you are, please stop confusing everyone. If one is not able to dissociate data protection with its rendering, there can be no progress! Again, @atylerrice asked for data protection…

People looking at such post want real solutions and not personal opinion on what is “impossible” or takes too much time to implement.

This is out of context for public work, plus a stream is not protected if it is not encrypted.

If you wish to discuss, in an organised fashion, the data rastering issue, the post is created and opened for suggestions…

I’m sorry if this confuses you, he asked for a solution to ensure no one can get the assets, i just suggested a reasonable solution as there is no encryption once it’s displayed in WebGL.

Is there a way to not allow the user to publicly download the 3d model and texture files that i’m showing?

Just search the web, you’ll get the same answers.

https://www.reddit.com/r/webgl/comments/2z22qe/encrypting_3d_models_for_webgl/

1 Like

No need to go in a wild search, if you look at this discourse, you will get a different answer. You need to secure the files by encryption from being publicly downloaded (as the title of this question specifies). Without this first action, there is no need to go further.

Then, if the person wants to protect the webGL buffers, it is another problematic. Some people are going to resolve this issue and others may want to take the risk without securing it. It will depend on their use cases.

@Fyrestar i find reasonable the answer that you have linked. @INF1N1T “No need to go in a wild search, if you look at this discourse, you will get a different answer”, isn’t a bit too pretentious? I’m sorry if I can look pedant at your eyes but I like threejs and I’m happy that finally there is a forum, and I would like that all the people that post answers and questions feels comfortable doing it, and not scared. Feel free to DM me for any clarification :wink:

1 Like

First, BMP and OBJ file up to the server to access prohibited by htaccess.

-----------htaccess--------------------------
<Files ~ "\.(obj|bmp|mtl)$">
  deny from all 
</Files>

order Allow,Deny
Allow from all
Deny from env=shutout
-------------------------------------

Next, in the program, call the php file with ‘GET’ using XMLHttpRequest.
The content of the php file should be as follows.

---------php----------------------------

	$bmpfile = 'xxx.bmp';	//bmp file

	$uri = 'data:' . mime_content_type($bmpfile) . ';base64,';
	$uri .= base64_encode(file_get_contents($bmpfile));

	$arr['bmp'] = $uri;

	$objfile = 'xxx.obj';	//obj file

	$arr['obj'] = file_get_contents($objfile);

	echo json_encode($arr);
-------------------------------------

Read BMP and OBJ file with responseText of JSON.parse.

With this, I do not link directly from the browser, so I think it is safe.

If “Publicly downloading files” means going into the developers to > finding the file > saving a local copy of it.
The first line of defence would be to encrypt the file which may come with some cost of performance.

But, if those file are already rendering on the screen, there is no ideal defence for it. The actual files can be dynamically recreated and can be downloaded.

One different solution can be : you can simply render whatever graphics you want on the server and send the image data as a png to the web page.

But again this method has it own limitations.

4 Likes

We figured out the way to corrupt the GLB files (Using an encryption method), Then load that file as Arraybuffer, Decode the file as text and load them in the viewer, Ultimately the loaded model would still appear corrupted to anyone who has downloaded through the inspector.

Do you have a source repo for this to share? Or would that effectively be giving the keys out to your decryption method?

We figured out the process of Encypting / Decrypting the GLB file (Not exactly an encyption more of a a corrupting the file and correct it back while loading,

You need to use a Hex editor and edit (Replace any character at the start and end of the file and note the location of the modification), Then save that as the the “Corrupted.GLB”.

In Threejs, Instead of GLB Loader, You should use the arraybuffer to read the GLB file as and replace the Corrupted places with the proper words / characters

(Eg, The GLB file always starts with GLTF (Position 0 to 3), So If I would have replaced that with something else then I should revert the characters at that positions back to “GLTF”).

And once the replace is done, Then you can directly load the array buffer and instantiate your model.

This whole method prevents anyone to open the GLB file in any 3D Modelling tools, It would just throw error messages that the model is corrupted.

4 Likes

I asked Chat GPT 4 Turbo for sample code. Here’s its answer. I have not checked if it works

This approach described for encrypting/decrypting (or more accurately, corrupting and restoring) GLB files is a clever strategy for deterring casual users from downloading and using 3D models outside of your application. It adds an extra layer of complexity for anyone trying to directly access the model files.

To implement this in Three.js using TypeScript, you would modify the standard GLB loading process to first adjust the ArrayBuffer of the GLB file, correcting the deliberate corruptions you made. Here’s a basic implementation of this idea:

  1. Load the ‘corrupted’ GLB file as an ArrayBuffer.
  2. Modify the ArrayBuffer to correct the intentional corruptions.
  3. Load the model from the corrected ArrayBuffer using Three.js’s GLTFLoader.

Here’s a TypeScript example that demonstrates this concept:

import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';

async function loadEncryptedModel(url: string): Promise<THREE.Group> {
  const loader = new GLTFLoader();
  
  // Function to fetch and correct the corrupted GLB file
  async function fetchAndCorrectModel(url: string): Promise<ArrayBuffer> {
    const response = await fetch(url);
    const buffer = await response.arrayBuffer();
    const view = new Uint8Array(buffer);

    // Correct the file - replace with your specific corrections
    // For example, if the first four bytes were changed, revert them back to 'GLTF' (0x47, 0x4C, 0x54, 0x46)
    view[0] = 0x47; // 'G'
    view[1] = 0x4C; // 'L'
    view[2] = 0x54; // 'T'
    view[3] = 0x46; // 'F'

    // Apply any other necessary corrections here

    return buffer;
  }

  const correctedBuffer = await fetchAndCorrectModel(url);

  return new Promise((resolve, reject) => {
    loader.parse(correctedBuffer, '', gltf => resolve(gltf.scene), reject);
  });
}

// Example usage (assuming your setup for scene, camera, and renderer)
loadEncryptedModel('path/to/corrupted/model.glb').then(model => {
  scene.add(model);
  // additional setup or manipulation of the model
}).catch(error => {
  console.error('Error loading the model:', error);
});

This code assumes that you know the exact modifications made to the GLB file and can reverse them by manipulating the ArrayBuffer directly. Keep in mind, as with any security measure on the client side, this method is not foolproof. A determined individual with enough technical knowledge could still potentially reverse-engineer this process to access the original model. However, it does add a significant hurdle for unauthorized access or use.

What’s the best uniform way to add watermarks? For textures, it’s easy since you can add the watermark to the texture but for models without textures, how can you uniformly add watermarks to the geometry?