-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
webgl #234
Comments
Q1 - answered: I just needed two canvas elements <div>
<canvas id="webglcanvas"></canvas>
<canvas id="webgl2canvas"></canvas>
</div> is there some benefit to creating the canvas on the fly? |
The gist is good. Always welcome... All credit for that one goes to https://github.com/CesiumGS/webglreport. My refactoring is minimal. There are a few techniques not in there, but worth checking out. These are mostly experimental ideas that can be used to determine trustworthy vs. suspicious GPUs. // Highlight common GPU brands
// gpu can be a string of the renderer or both the vendor and renderer
function getGpuBrand(gpu) {
if (!gpu) return
const gpuBrandMatcher = /(adreno|amd|apple|intel|llvm|mali|microsoft|nvidia|parallels|powervr|samsung|swiftshader|virtualbox|vmware)/i
const brand = (
/radeon/i.test(gpu) ? 'AMD' :
/geforce/i.test(gpu) ? 'NVIDIA' :
( (gpuBrandMatcher.exec(gpu) || [])[0] || 'Other' )
)
return brand
}
// Takes the parameter object and generate a fingerprint of sorted numeric values
// This can be used to create a known good hash table and known brands can be labelled for each hash.
function generateParamFingerprint(parameters) {
if (!parameters) return
return '' + [
...new Set(Object.values(parameters)
.filter((val) => val && typeof val != 'string')
.flat()
.map((val) => Number(val))),
].sort((a, b) => (a - b))
} |
A premade canvas in the HTML can sometimes bypass scripts observing |
|
I forgot to add the sections like "Vertex Shader" and "Rasterizer", but these can be determined based on the property names. We just need to create a map. parameterType = {
'Vertex Shader': [
'MAX_VERTEX_ATTRIBS',
'MAX_VERTEX_TEXTURE_IMAGE_UNITS',
'MAX_VERTEX_UNIFORM_VECTORS',
]
}
if (ParameterType['Vertex Shader'].includes(propertyName)) {
// add to Vertex Shader section
} |
I merge as a final simplification, but also check and flag mismatch behind the scenes. I recall an incident where a mismatch was valid, so I just treat it as questionable. |
We can trap the error and push to a global collection. There are a few places different errors might get thrown due to users disabling or blocking the API, or parts of the API. |
hmmm, so I'm not sure how I want to present all this info - where is all the experimental stuff? I mean we can see webgl and webgl2. e.g. here's just checking for support. https://browserleaks.com/webgl has THREE toggles. Is this info in there (sorry for being a lazy bum but not into learning about webgl right now, lol) or it something we need to add e.g. let types = ["webgl", "webgl2", "experimental-webgl"]
types.forEach(function(type){
try {
let canvas = window.document.createElement("canvas")
try {
var context = canvas.getContext(type)
if (!context) {
throw new Error()
}
console.log(type, "supported")
} catch(e) {
console.log(type, "not supported")
}
} catch(e) {
console.log("canvas failed")
}
}) I think I can just take the objects and pull things out - I need to check various things as RFP protected, so they need to be separate.
doh. nothing to remove. nice. BTW not creating the canvas is a tiny perf win :) woo! |
can you add that to your gist so I can copy it, thanks |
Refactored: https://gist.github.com/abrahamjuliot/7baf3be8c451d23f7a8693d7e28a35e2
|
awesome, thx |
the gpuBrand is redundant (but nice) - I can drop that the gpuHash doesn't make much sense to me - sorting values could/would create collisions ? for example on it's own
This doesn't make a good fingerprint for max entropy, but I get it, it's a nice wee string. Unless I'm missing something |
let gpuV = cleanFn(parameters.UNMASKED_VENDOR_WEBGL),
gpuR = cleanFn(parameters.UNMASKED_RENDERER_WEBGL)
const gpu = String([gpuV, gpuR]) edit: well, it does handle it, it's just not very reader friendly :) |
I'm confused. Top is TB (which has RFP webgl mitigations - you get the same result in FF with RFP enabled), bottom is nightly with no RFP. The bottom test looks fine, but at first glance seem to have duplication, but the top test - why are we not returning a https://bugzilla.mozilla.org/show_bug.cgi?id=1337157 - lemme look at this. I know it's supposed to return undefined or blanks and/or const Categories = {
'debugRendererInfo': [
'UNMASKED_VENDOR_WEBGL',
'UNMASKED_RENDERER_WEBGL',
], // snip
}
parameters = { // snip
UNMASKED_VENDOR_WEBGL: getUnmasked(context, 'UNMASKED_VENDOR_WEBGL'),
UNMASKED_RENDERER_WEBGL: getUnmasked(context, 'UNMASKED_RENDERER_WEBGL')
}
parameters.DIRECT_3D = /Direct3D|D3D(\d+)/.test(parameters.UNMASKED_RENDERER_WEBGL)
gpuVendor = parameters.UNMASKED_VENDOR_WEBGL
gpuRenderer = parameters.UNMASKED_RENDERER_WEBGL |
so |
Yeah, gpu is non-essential. I forgot. GPU showing up under render is this issue. It can be ignored, but the way to around is to feature detect the version and then use renderer instead of debug info, but its only necessary to remove the console warning. |
This too is not needed. It can be useful to put known good fingerprints into a lookup table (similar to known good audio sums). Clashing is likely and okay, as long random WebGL fingerprints find it hard to fit in. I'm guessing, based on limited data on CreepJS, the table size would require no more than 100 hashes. Everything unknown can be questioned until it is established trustworthy. This is more of a test concept, I suppose. It would require many samples. |
tis all cool. The RFP notation should be pretty simple now I refreshed my memory as to what we were doing with it - there's more to it than just vendor/renderer. But easy to check the few places it shows.
I log all errors as part of the error entropy :)
no worries. I get it was experimental - but this is gecko and all I care about is Tor Browser and RFP. If I check prototype lies (I'll need to check) then I can just return the whole thing as useless (might revisit later) when we collect data from surveys (via a Tor Browser annual or bi-annual FP drive - 100% opt-in with one test per profile), we can just reject collecting tainted data based on prototype lies alone - i.e either it is all empty or it matches NoScripts signature |
There's also these anti-detection browsers that fake the GPUs at engine level. No prototype lies. For Firefox, I think they use what is called "Stealthfox Browser". The only way I'm aware of to detect them is by using a look-up table of known good hashes. WebGL is too high entropy for a local lookup, but this lower entropy hash works. I have not used it on CreepJS, but I have the data visually from last 60 days of bad traffic. |
gummy bear browsers :) lols ... I'm not too worried about it TBH, I need to focus on actual TB and FF + RFP users |
Something I discovered, many of them have a frozen max stack size fingerprint. Something with the way it's compiled, I guess. |
I'm not entirely sure what you mean by that, tell me more :) - you had me at "something" Yeah, math PoCs are great, like known pixel tests, joining chars vs individual chars in textmetrics width, domrect etc. Enumerating goodness is hard and no bulletproof - so I understand the mini simplified hash - like the simplified (less measurements) of https://arkenfox.github.io/TZP/tests/domrectspoofratio.html that covers multiple chrome results I just had to drop enumerating goodness for audio in FF (TZP 2.0 is gecko only) - math library changes on android, and they will change again, and then RFP is also doing something with it (or it will apply for all) - https://bugzilla.mozilla.org/show_bug.cgi?id=1358149#c26 |
do you mean recursion, stack depth, rather than some webgl thing? |
Yeah, recursion, stack depth. I have not tested for Firefox, but it's somewhat of an unbeatable fingerprint for custom Chrome builds that are slow to update. |
OT: but I had an email exchange with a moz dev about this, and it's a good (fuzzy) FP for determining ion and jit etc |
@abrahamjuliot - is this uptodate? https://gist.github.com/abrahamjuliot/7baf3be8c451d23f7a8693d7e28a35e2
I don't want to re-invent the wheel, so want to use your code (accredited) if that's OK - please advise
ATM, I only want to collect the parameters, extensions, vendor, etc - not any actual rendering
so some questions
Q1
https://gist.github.com/abrahamjuliot/7baf3be8c451d23f7a8693d7e28a35e2#file-webgl-js-L91-L94
so here, I wanted to use an already created canvas (I think it saves time)
but I get errors for webgl2 (webgl is fine)
I also don't see where you remove and cleanup the
document.createElement('canvas')
- remember, TZP allows section reruns so I don't want to end up with dozens of canvas elementsQ2
what is newmethods meant to signify in webgl2 ?
Q3
for data collection/entropy - I am not webgl savvy - but remember in the old TZP repo we discussed, and I mocked up, a webgl section that would return webgl, webgl2, experimental results - a bit like
how is this all reflected in the objects in the console? I'm a bit lost
Q4
how/what are you doing with this data to only show one set of parameters on creepy - I can see that some are identical in webgl 1 vs 2 - and there is a diffs output. Are you merging these?
Q5?
I guess I'll have to play to catch errors and return that - you seem to just console them and return undefined (I guess I could do that)
The text was updated successfully, but these errors were encountered: