SlideShare a Scribd company logo
1 of 143
@vazac
How to identify bad third-
parties on your page
Charles Vazac
@vazac
@vazac
@vazac
@vazac
@vazac
https://www.w3.org/webperf/
@vazac
● 36f11e49.akstat.io
● 4448044.fls.doubleclick.net
● 642-skn-449.mktoresp.com
● 79792546.va.cobrowse.liveperson.net
● accdn.lpsnmedia.net
● akamai.com
● analytics.twitter.com
● api.company-target.com
● bat.bing.com
● bizographics.com
● c.go-mpulse.net
● cdn.dashjs.org
● cdnssl.clicktale.net
● cm.g.doubleclick.net
● d.company-target.com
● d26x5ounzdjojj.cloudfront.net
● dc.ads.linkedin.com
● drvizd1lyevz4.cloudfront.net
● ds-aksb-a.akamaihd.net
● e02.optimix.asia
● google-analytics.com
● google.com
● googleads.g.doubleclick.net
● googleadservices.com
● googletagmanager.com
● graph.facebook.com
● insight.adsrvr.org
● j02.optimix.asia
● j02.optimix.asia
● linkedin.com
● lpcdn.lpsnmedia.net
● lptag.liveperson.net
● m.addthis.com
● m.addthisedge.com
● match.adsrvr.org
● match.prod.bidr.io
● munchkin.marketo.net
● pixel.quantserve.com
● pubads.g.doubleclick.net
● px.ads.linkedin.com
● s.ml-attr.com
● s7.addthis.com
● scripts.demandbase.com
● secure.adnxs.com
● secure.quantserve.com
● sjs.bizographics.com
● snap.licdn.com
● sp.adbrn.com
● static.ads-twitter.com
● stats.g.doubleclick.net
● sync.adap.tv
● sync.adaptv.advertising.com
● t.co
● tags.w55c.net
● unpkg.com
● us-east-1.dc.ads.linkedin.com
@vazac
https://twitter.com/zachleat/status/363053721258700800
@vazac http://www.tooled-up.com/
@vazac
https://twitter.com/Tobi042/status/648946436445446145
@vazac
Browser native overrides
● forge
● guerrilla patch
● hijack
● hook
● instrument
● intercept
● mock
● monkey-patch
● override
● overwrite
● polyfill, prollyfill, notifill, ponyfill
● proxy
● shadow
● sham
● shim
● shiv
● spoof
● stub
● swizzle
● trap
● wrap
@vazac
https://twitter.com/aweary/status/913519003426988032
@vazac
What is a third-party
“Code in your site that is managed by someone else” - Guy Podjarny (@guypod)
@vazac
Why do we sometimes need third-parties?
● JS / CSS Frameworks
● Analytics (yay! boomerang!)
● Ads :(
● Customer engagement (intercom.io)
● Comments widgets
● Social Media
● A/B Testing
● Web Fonts
● Accessibility Tools
● .... and yes, jQuery! (30KB minified and gzipped)
@vazac
What can go wrong?
● Page breakage
○ Script errors
○ Bad polyfills
○ Namespace collisions
○ SPOF
https://twitter.com/patmeenan/status/938071367525781506
@vazac
What can go wrong?
● Page breakage
● Performance Issues
○ Slow page load
○ Janky user experience
○ Redirect chains
○ Battery drain
○ Memory Leaks
@vazac
What can go wrong?
● Page breakage
● Performance Issues
● Privacy & security
@vazac
https://twitter.com/calrgn/status/913525736836931585
@vazac
https://twitter.com/nytimes/status/3958547840
@vazac
What can go wrong?
● Page breakage
● Performance Issues
● Privacy & security
● Makes debugging *your* stuff really hard!
https://twitter.com/slicknet/status/997248009778876416
@vazac
https://www.tumblr.com/search/i've%20made%20a%20huge%20mistake%20gif
@vazac
Example #1
“Lazy loader” library
// lazy loading package
window.requestAnimationFrame = window.requestAnimationFrame || setTimeout
@vazac
Example #1
“Lazy loader” library
// lazy loading package
window.requestAnimationFrame = window.requestAnimationFrame || setTimeout
// in-page feature detection
if (typeof requestAnimationFrame === 'function') {
requestAnimationFrame(function() {
/* fancy animation codez */
})
}
@vazac
Example #1
“Lazy loader” library
window.requestAnimationFrame = window.requestAnimationFrame || setTimeout
// in-page feature detection
if (typeof requestAnimationFrame === 'function') {
var requestId = requestAnimationFrame(function() {
/* fancy animation codez */
})
// sometime later
cancelAnimationFrame(requestId)
}
@vazac
Example #1
“Lazy loader” library
window.requestAnimationFrame = window.requestAnimationFrame || setTimeout
// in-page feature detection
if (typeof requestAnimationFrame === 'function') {
var requestId = requestAnimationFrame(function() {
/* fancy animation codez */
})
// sometime later
cancelAnimationFrame(requestId)
}
Uncaught ReferenceError: cancelAnimationFrame is not defined
@vazac
Example #2
“Accelerated JavaScript animation” framework
@vazac
Example #2
var performance = (function() {
var perf = window.performance || {};
if (!Object.prototype.hasOwnProperty.call(perf, 'now')) {
var nowOffset = perf.timing && perf.timing.domComplete ? perf.timing.domComplete : (new
Date()).getTime();
perf.now = function() {
return (new Date()).getTime() - nowOffset;
};
}
return perf;
})();
@vazac
Example #2
var performance = (function() {
var perf = window.performance || {};
if (!Object.prototype.hasOwnProperty.call(perf, 'now')) {
var nowOffset = perf.timing && perf.timing.domComplete ? perf.timing.domComplete : (new
Date()).getTime();
perf.now = function() {
return (new Date()).getTime() - nowOffset;
};
}
return perf;
})();
Should be perf.timing.navigationStart
@vazac
Example #3
“Front End Optimization”
@vazac
Example #3
try {
Object.defineProperty(document, 'readyState', {
get: function() {
return somethingElse
}
})
} catch (e) {}
@vazac
Example #3
window.addEventListener = (function(addEventListener) {
return function() {
if (['load', 'readyStateChanged'].indexOf(arguments[0]) !== -1) {
// collect these and execute them later
return
}
return addEventListener.apply(this, arguments)
}
})(window.addEventListener)
@vazac
Example #3
window.onload = function() {
// but they left this one alone
}
@vazac
document.hasOwnProperty('readyState')
Example #3 - detection
@vazac
document.hasOwnProperty('readyState')
// false
Example #3 - detection
@vazac
document.hasOwnProperty('readyState')
// false
Example #3 - detection
Object.defineProperty(document, 'readyState', {
/* ... */
})
@vazac
Example #3 - detection
document.hasOwnProperty('readyState')
// false
document.hasOwnProperty('readyState')
Object.defineProperty(document, 'readyState', {
/* ... */
})
@vazac
Example #3 - detection
document.hasOwnProperty('readyState')
// false
document.hasOwnProperty('readyState')
// true
Object.defineProperty(document, 'readyState', {
/* ... */
})
@vazac
Example #4
“RUM analytics” script (**cough cough** boomerang)
@vazac
Example #4
var addEventListener = EventTarget.prototype.addEventListener
EventTarget.prototype.addEventListener = function(type, callback) {
addEventListener(type, function() {
/* intervene here */
callback()
})
}
@vazac
Example #4
var addEventListener = EventTarget.prototype.addEventListener
EventTarget.prototype.addEventListener = function(type, callback) {
addEventListener(type, function() {
/* intervene here */
callback()
})
}
document.body.addEventListener('click', handler)
@vazac
Example #4
var addEventListener = EventTarget.prototype.addEventListener
EventTarget.prototype.addEventListener = function(type, callback) {
addEventListener(type, function() {
/* intervene here */
callback()
})
}
document.body.addEventListener('click', handler)
document.body.removeEventListener('click', handler)
@vazac
Example #4
document.body.addEventListener('click', handler)
document.body.removeEventListener('click', handler)
// ^^^ does NOT work because `handler` was never attached!
var addEventListener = EventTarget.prototype.addEventListener
EventTarget.prototype.addEventListener = function(type, callback) {
addEventListener(type, function() {
/* intervene here */
callback()
})
}
@vazac
Example #4
document.body.addEventListener('click', handler)
document.body.removeEventListener('click', handler)
// ^^^ does NOT work because `handler` was never attached!
var addEventListener = EventTarget.prototype.addEventListener
EventTarget.prototype.addEventListener = function(type, callback) {
addEventListener(type, function() {
/* intervene here */
callback()
})
}
@vazac
https://tenor.com/view/bananastand-burn-it-down-banana-gif-8351164
@vazac
Example #1
https://twitter.com/kinsi55/status/888439631318061057
@vazac
@vazac
Example #2
setInterval(function() {
debugger
}, 10)
https://stackoverflow.com/questions/7798748/find-out-whether-chrome-console-is-open/30638226#30638226
@vazac
Circumvention
Local Overrides (Chrome 65+)
@vazac
@vazac
Example #3
“Too many secrets”
● Ads
● Ad blockers
● Ad blocker blockers
● Ad infinitum
@vazac
DevTools detection #1
setInterval(function () {
const threshold = 160
const {outerWidth, innerWidth, outerHeight, innerHeight} = window
window.devToolsOpen = outerWidth - innerWidth > threshold ||
outerHeight - innerHeight > threshold
}, 500);
@vazac
function isDevToolsOpen() {
const element = new Image()
let open = false
Object.defineProperty(element, 'id', {
get: function () {
open = true // this is the "trap"
}
})
console.log(element)
return open
}
DevTools detection #2
https://stackoverflow.com/questions/7798748/find-out-whether-chrome-console-is-open/30638226#30638226
@vazac
Circumvention
@vazac
Circumvention
// using tampermonkey
window.open()
@vazac
Circumvention
// from devtools of the blank page
var iframes = opener.document.getElementsByTagName('iframe')
// using tampermonkey
window.open()
@vazac
Example #4
“Super phishing”
@vazac
@vazac
http://78.media.tumblr.com/tumblr_maeb36MSBm1qgb321o1_500.gif
@vazac
Unbound listeners
var car = new Car()
car.start()
@vazac
Unbound listeners
var car = new Car()
car.start()
function Car() { /* ... */}
Car.prototype.start = function() {
// what is `this`?
}
@vazac
Unbound listeners
var car = new Car()
car.start()
function Car() { /* ... */}
Car.prototype.start = function() {
// `this` will be `car`
}
@vazac
Unbound listeners
var car = new Car()
var start = car.start
start()
@vazac
Unbound listeners
var car = new Car()
var start = car.start
start()
function Car() { /* ... */}
Car.prototype.start = function() {
// what is `this`?
}
@vazac
Unbound listeners
var car = new Car()
var start = car.start
start()
function Car() { /* ... */}
Car.prototype.start = function() {
// `this` will be `window`
}
@vazac
Unbound listeners
window.addEventListener('load', function loadHandlerBound(e) {
// what is `this`?
})
@vazac
Unbound listeners
window.addEventListener('load', function loadHandlerBound(e) {
// `this` is `window`
})
@vazac
Unbound listeners
window.addEventListener('load', function loadHandlerBound(e) {
// `this` is `window`
})
var method = window.addEventListener
method('load', function loadHandlerUnbound(e) {
// what is `this`?
})
@vazac
Unbound listeners
window.addEventListener('load', function loadHandlerBound(e) {
// `this` is `window`
})
var method = window.addEventListener
method('load', function loadHandlerUnbound(e) {
// `this` is `window`
})
@vazac
Unbound listeners
var _addEventListener = top.EventTarget.prototype.addEventListener
top.EventTarget.prototype.addEventListener = function intervene() {
// intervene here
return _addEventListener.apply(this, arguments)
}
@vazac
Unbound listeners
window.addEventListener('load', function loadHandlerBound(e) {
// what is `this`?
})
@vazac
Unbound listeners
window.addEventListener('load', function loadHandlerBound(e) {
// `this` is `window`
})
@vazac
Unbound listeners
window.addEventListener('load', function loadHandlerBound(e) {
// `this` is `window`
})
var method = window.addEventListener
method('load', function loadHandlerUnbound(e) {
// what is `this`?
})
@vazac
Unbound listeners
var _addEventListener = top.EventTarget.prototype.addEventListener
top.EventTarget.prototype.addEventListener = function intervene() {
// intervene here
return _addEventListener.apply(this, arguments)
}
@vazac
Unbound listeners
var _addEventListener = top.EventTarget.prototype.addEventListener
top.EventTarget.prototype.addEventListener = function intervene() {
// intervene here
return _addEventListener.apply(this, arguments)
}
var method = window.addEventListener
method('load', function loadHandlerUnbound(e) {
// what is `this`?
})
@vazac
Unbound listeners
var _addEventListener = top.EventTarget.prototype.addEventListener
top.EventTarget.prototype.addEventListener = function intervene() {
// intervene here
return _addEventListener.apply(this, arguments)
}
var method = window.addEventListener
method('load', function loadHandlerUnbound(e) {
// what is `this`?
})
@vazac
Unbound listeners
var _addEventListener = top.EventTarget.prototype.addEventListener
top.EventTarget.prototype.addEventListener = function intervene() {
// intervene here
return _addEventListener.apply(this, arguments)
}
var method = window.addEventListener
method('load', function loadHandlerUnbound(e) {
// what is `this`?
})
@vazac
Unbound listeners
var _addEventListener = top.EventTarget.prototype.addEventListener
top.EventTarget.prototype.addEventListener = function intervene() {
// intervene here
return _addEventListener.apply(this, arguments)
}
var method = window.addEventListener
method('load', function loadHandlerUnbound(e) {
// `this` is the IFRAME
})
@vazac
Unbound listeners
var method = window.addEventListener
window.addEventListener =
function unboundAddEventListener(eventName, handler) {
method(eventName, handler)
}
@vazac
https://daicynotdaisy.wordpress.com/2010/10/page/2/
@vazac
Table stakes
● HTTPS only
● Don’t produce scripts errors
● No sync XHR
● Don’t pollute the global namespace
● Don’t ship down ALL of jQuery
● Handle “both sides”
● Test on old browsers
● Don’t slow down unload
● Don’t attach too many handlers
● Polyfills
○ Ensure spec compliance
○ Don’t let them rot!
@vazac
Be a good citizen
raven.js (sentry.io)
@vazac
@vazac
EventTarget.prototype.addEventListener = (function(addEventListener) {
return function(type, callback) {
addEventListener(type, function() {
/* ... */
callback()
/* ... */
})
}
})(EventTarget.prototype.addEventListener)
@vazac
EventTarget.prototype.addEventListener = (function(addEventListener) {
return function(type, callback) {
addEventListener(type, function() {
/* ... */
callback()
/* ... */
})
}
})(EventTarget.prototype.addEventListener)
document.body.addEventListener('click', function(e) {
console.info('CLICKED!') // CLICKED!
})
@vazac
EventTarget.prototype.addEventListener = (function(addEventListener) {
return function(type, callback) {
addEventListener(type, function() {
/* ... */
callback()
/* ... */
})
}
})(EventTarget.prototype.addEventListener)
document.body.addEventListener('click', function(e) {
console.info('CLICKED!') // CLICKED!
})
@vazac
EventTarget.prototype.addEventListener = (function(addEventListener) {
return function() {
var args = Array.prototype.slice.call(arguments)
var callback = args[1]
args[1] = function() {
/* ... */
callback()
/* ... */
}
addEventListener.apply(undefined, args)
}
})(EventTarget.prototype.addEventListener)
@vazac
EventTarget.prototype.addEventListener = (function(addEventListener) {
return function() {
var args = Array.prototype.slice.call(arguments)
var callback = args[1]
args[1] = function() {
/* ... */
callback()
/* ... */
}
addEventListener.apply(undefined, args)
}
})(EventTarget.prototype.addEventListener)
document.body.addEventListener('click', function(e) {
console.info('CLICKED!') // CLICKED!
console.info(e.timeStamp)
})
@vazac
EventTarget.prototype.addEventListener = (function(addEventListener) {
return function() {
var args = Array.prototype.slice.call(arguments)
var callback = args[1]
args[1] = function() {
/* ... */
callback()
/* ... */
}
addEventListener.apply(undefined, args)
}
})(EventTarget.prototype.addEventListener)
document.body.addEventListener('click', function(e) {
console.info('CLICKED!') // CLICKED!
console.info(e.timeStamp)
})
Uncaught TypeError: Cannot read property 'timeStamp' of undefined
@vazac
EventTarget.prototype.addEventListener = (function(addEventListener) {
return function() {
var args = Array.prototype.slice.call(arguments)
var callback = args[1]
args[1] = function() {
/* ... */
callback.apply(undefined, arguments)
/* ... */
}
addEventListener.apply(undefined, args)
}
})(EventTarget.prototype.addEventListener)
@vazac
EventTarget.prototype.addEventListener = (function(addEventListener) {
return function() {
var args = Array.prototype.slice.call(arguments)
var callback = args[1]
args[1] = function() {
/* ... */
callback.apply(undefined, arguments)
/* ... */
}
addEventListener.apply(undefined, args)
}
})(EventTarget.prototype.addEventListener)
document.body.addEventListener('click', function(e) {
console.info('CLICKED!') // CLICKED!
console.info(e.timeStamp)
console.info(this.tagName)
})
@vazac
EventTarget.prototype.addEventListener = (function(addEventListener) {
return function() {
var args = Array.prototype.slice.call(arguments)
var callback = args[1]
args[1] = function() {
/* ... */
callback.apply(undefined, arguments)
/* ... */
}
addEventListener.apply(undefined, args)
}
})(EventTarget.prototype.addEventListener)
document.body.addEventListener('click', function(e) {
console.info('CLICKED!') // CLICKED!
console.info(e.timeStamp) // 949.3050000000001
console.info(this.tagName)
})
@vazac
EventTarget.prototype.addEventListener = (function(addEventListener) {
return function() {
var args = Array.prototype.slice.call(arguments)
var callback = args[1]
args[1] = function() {
/* ... */
callback.apply(undefined, arguments)
/* ... */
}
addEventListener.apply(undefined, args)
}
})(EventTarget.prototype.addEventListener)
document.body.addEventListener('click', function(e) {
console.info('CLICKED!') // CLICKED!
console.info(e.timeStamp) // 949.3050000000001
console.info(this.tagName) // undefined :(
})
@vazac
EventTarget.prototype.addEventListener = (function(addEventListener) {
return function() {
var args = Array.prototype.slice.call(arguments)
var callback = args[1]
args[1] = function() {
/* ... */
callback.apply(this, arguments)
/* ... */
}
addEventListener.apply(this, args)
}
})(EventTarget.prototype.addEventListener)
@vazac
EventTarget.prototype.addEventListener = (function(addEventListener) {
return function() {
var args = Array.prototype.slice.call(arguments)
var callback = args[1]
args[1] = function() {
/* ... */
callback.apply(this, arguments)
/* ... */
}
addEventListener.apply(this, args)
}
})(EventTarget.prototype.addEventListener)
document.body.addEventListener('click', function(e) {
console.info('CLICKED!') // CLICKED!
console.info(e.timeStamp) // 949.3050000000001
console.info(this.tagName)
})
@vazac
EventTarget.prototype.addEventListener = (function(addEventListener) {
return function() {
var args = Array.prototype.slice.call(arguments)
var callback = args[1]
args[1] = function() {
/* ... */
callback.apply(this, arguments)
/* ... */
}
addEventListener.apply(this, args)
}
})(EventTarget.prototype.addEventListener)
document.body.addEventListener('click', function(e) {
console.info('CLICKED!') // CLICKED!
console.info(e.timeStamp) // 949.3050000000001
console.info(this.tagName) // BODY
})
@vazac
EventTarget.prototype.addEventListener = (function(addEventListener) {
return function() {
var args = Array.prototype.slice.call(arguments)
var callback = args[1]
args[1] = function() {
/* ... */
callback.apply(this, arguments)
/* ... */
}
addEventListener.apply(this, args)
}
})(EventTarget.prototype.addEventListener)
document.body.addEventListener('click', function(e) {
console.info('CLICKED!') // CLICKED!
console.info(e.timeStamp) // 949.3050000000001
console.info(this.tagName) // BODY
foo.bar()
})
@vazac
EventTarget.prototype.addEventListener = (function(addEventListener) {
return function() {
var args = Array.prototype.slice.call(arguments)
var callback = args[1]
args[1] = function() {
/* ... */
callback.apply(this, arguments)
/* ... */
}
addEventListener.apply(this, args)
}
})(EventTarget.prototype.addEventListener)
document.body.addEventListener('click', function(e) {
console.info('CLICKED!') // CLICKED!
console.info(e.timeStamp) // 949.3050000000001
console.info(this.tagName) // BODY
foo.bar()
})
@vazac
EventTarget.prototype.addEventListener = (function(addEventListener) {
return function() {
var args = Array.prototype.slice.call(arguments)
var callback = args[1]
args[1] = function() {
/* ... */
var e
try {
callback.apply(this, arguments)
} catch(_e) {
e = _e
}
/* ... */
if (e) throw e
}
addEventListener.apply(this, args)
}
})(EventTarget.prototype.addEventListener)
@vazac
EventTarget.prototype.addEventListener = (function(addEventListener) {
return function() {
var args = Array.prototype.slice.call(arguments)
var callback = args[1]
args[1] = function() {
/* ... */
var e
try {
callback.apply(this, arguments)
} catch(_e) {
e = _e
}
/* ... */
if (e) throw e
}
addEventListener.apply(this, args)
}
})(EventTarget.prototype.addEventListener)
@vazac
EventTarget.prototype.addEventListener = (function(addEventListener) {
return function() {
var args = Array.prototype.slice.call(arguments)
var callback = args[1]
args[1] = function() {
/* ... */
var e
try {
callback.apply(this, arguments)
} catch(_e) {
e = _e
}
/* ... */
if (e) throw e
}
addEventListener.apply(this, args)
}
})(EventTarget.prototype.addEventListener)
@vazac
EventTarget.prototype.addEventListener = (function(addEventListener) {
return function() {
var args = Array.prototype.slice.call(arguments)
var callback = args[1]
args[1] = function() {
/* ... */
var e
try {
callback.apply(this, arguments)
} catch(_e) {
e = _e
}
/* ... */
if (e) throw e
}
addEventListener.apply(this, args)
}
})(EventTarget.prototype.addEventListener)
@vazac
Let’s talk about the `console`
● Don’t be chatty
● Don’t clear it
● Don’t block *my* messages
● Don’t emit warnings
@vazac
Let’s talk about directives
<link
href='http://tpc.googlesyndication.com/safeframe/1-0-9/html/container.html' />
<script
src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js?ver=4.8.2'>
</script>
@vazac
Let’s talk about stack traces
Uncaught ReferenceError: s is not defined
at a (https://js.example.com/bundles/1.2/metrics:1:22530)
at post (https://js.example.com/bundles/1.2/metrics:1:24939)
at TLT</</</n[i] (https://js.example.com/bundles/1.2/metrics:1:14165)
at TLT.ModuleContext</</f[o]</< (https://js.example.com/bundles/1.2/metrics:1:19916)
at e (https://js.example.com/bundles/1.2/metrics:1:44663)
at onevent (https://js.example.com/bundles/1.2/metrics:1:45023)
at _publishEvent (https://js.example.com/bundles/1.2/metrics:1:11026)
at v/< (https://js.example.com/bundles/1.2/metrics:1:32162)
at dispatch (https://js.example.com/bundles/1.6.6/vendor:1:47613)
at add/a.handle (https://js.example.com/bundles/1.6.6/vendor:1:44402)
at wrap/< (https://c.go-mpulse.net/boomerang/XXXXX-XXXXX-XXXXX-XXXXX-XXXXX:15:8516)
at e/f.submitLogin/< (https://js.example.com/bundles/17.6.21.37271/app:1:178948)
at nt/o.success/< (https://js.example.com/bundles/1.6.6/vendor:1:413549)
at nt (https://js.example.com/bundles/1.6.6/vendor:1:430936)
at h/< (https://js.example.com/bundles/1.6.6/vendor:1:431108)
at $eval (https://js.example.com/bundles/1.6.6/vendor:1:438663)
at $digest (https://js.example.com/bundles/1.6.6/vendor:1:437152)
at $apply (https://js.example.com/bundles/1.6.6/vendor:1:438946)
at ut (https://js.example.com/bundles/1.6.6/vendor:1:414086)
at it (https://js.example.com/bundles/1.6.6/vendor:1:415961)
at vp/</k.onload (https://js.example.com/bundles/1.6.6/vendor:1:416510)
@vazac
http://wegotthiscovered.com/tv/jokes-missed-arrested-development/5/
@vazac
Code defensively
navigator.sendBeacon &&
navigator.sendBeacon(...)
if (typeof navigator.sendBeacon !== 'undefined') {
navigator.sendBeacon(...)
}
if (typeof navigator.sendBeacon === 'function') {
navigator.sendBeacon(...)
} ☑
☒
☒navigator.sendBeacon = {}
@vazac
Code defensively
∞
const nodeList = document.getElementsByTagName('input')
while (nodeList.length) {
nodeList[0].parentNode.removeChild(nodeList[0])
}
const nodeList = document.getElementsByTagName('input')
let length = nodeList.length
while (length--) {
nodeList[0].parentNode &&
nodeList[0].parentNode.removeChild(nodeList[0])
}
☑
Element.prototype.removeChild = function() {}
@vazac
Content Security Policy
Content-Security-Policy: default-src 'self' scripts.example.com
Content-Security-Policy: default-src 'self'
Content-Security-Policy: default-src 'self' *.googleapis.com
Content-Security-Policy: script-src 'sha256-qznLcsROx4GACP2dm0UCKCzCG-
HiZ1guq6ZZDob_Tng='
@vazac
Cross-Origin IFRAMEs
// from https://www.example.com
<iframe src='https://third-party.example.com/social-media.js' />
// www.example.com !== third-party.example.com
@vazac
Sandboxing IFRAMEs
● allow-scripts
● allow-same-origin
● allow-forms
● allow-popups
● allow-top-navigation
● allow-top-navigation-by-user-activation
<iframe src='https://third-party.com/widget.html' sandbox='' />
@vazac
http://arresteddevelopment.wikia.com/
@vazac
Freeze
● Object.defineProperty
Object.defineProperty(console, 'log', {
writable: false, // shut off assignment
configurable: false, // shut off changes to the property descriptor
})
@vazac
Freeze
● Object.freeze
Object.freeze(console)
@vazac
Freeze
● freeze.js (https://github.com/cvazac/freeze.js)
const {freeze, thaw} = require('freeze.js')
freeze('console.clear')
freeze('document.readyState')
freeze('XMLHttpRequest')
freeze('XMLHttpRequest.prototype.open')
freeze('MyClass.prototype.method')
● nops calls to Object.defineProperty
● nops calls to Object.assign
● nops setter attempts
@vazac
http://www.fanpop.com/clubs/arrested-development/picks/show/702020/better-pi-gene-parmesan-ice
@vazac
isNativeFunction #1
function isNativeFunction(fn) {
return typeof fn === 'function' &&
/[native code]/.test(String(fn))
}
@vazac
isNativeFunction(XMLHttpRequest) // true
isNativeFunction #1
function isNativeFunction(fn) {
return typeof fn === 'function' &&
/[native code]/.test(String(fn))
}
@vazac
window.XMLHttpRequest = function() { /* ... */ }
isNativeFunction(XMLHttpRequest) // true
isNativeFunction #1
function isNativeFunction(fn) {
return typeof fn === 'function' &&
/[native code]/.test(String(fn))
}
@vazac
isNativeFunction(XMLHttpRequest) // true
isNativeFunction(XMLHttpRequest) // false
window.XMLHttpRequest = function() { /* ... */ }
isNativeFunction #1
function isNativeFunction(fn) {
return typeof fn === 'function' &&
/[native code]/.test(String(fn))
}
@vazac
isNativeFunction(XMLHttpRequest) // true
isNativeFunction(XMLHttpRequest) // false
isNativeFunction #1
function isNativeFunction(fn) {
return typeof fn === 'function' &&
/[native code]/.test(String(fn))
}
window.XMLHttpRequest = function() { /* ... */ }
window.XMLHttpRequest.toString = function() {
return '[native code]'
}
@vazac
isNativeFunction(XMLHttpRequest) // true
isNativeFunction(XMLHttpRequest) // false
isNativeFunction(XMLHttpRequest) // **true**
(false positive)
isNativeFunction #1
function isNativeFunction(fn) {
return typeof fn === 'function' &&
/[native code]/.test(String(fn))
}
window.XMLHttpRequest = function() { /* ... */ }
window.XMLHttpRequest.toString = function() {
return '[native code]'
}
@vazac
isNativeFunction #1
function isNativeFunction(fn) {
return typeof fn === 'function' &&
/[native code]/.test(Function.prototype.toString.call(fn))
}
@vazac
isNativeFunction(XMLHttpRequest) // true
isNativeFunction #1
function isNativeFunction(fn) {
return typeof fn === 'function' &&
/[native code]/.test(Function.prototype.toString.call(fn))
}
@vazac
isNativeFunction(XMLHttpRequest) // true
window.XMLHttpRequest = function() { /* ... */ }
isNativeFunction #1
function isNativeFunction(fn) {
return typeof fn === 'function' &&
/[native code]/.test(Function.prototype.toString.call(fn))
}
@vazac
window.XMLHttpRequest = function() { /* ... */ }
isNativeFunction(XMLHttpRequest) // true
isNativeFunction(XMLHttpRequest) // false
isNativeFunction #1
function isNativeFunction(fn) {
return typeof fn === 'function' &&
/[native code]/.test(Function.prototype.toString.call(fn))
}
@vazac
isNativeFunction(XMLHttpRequest) // true
isNativeFunction(XMLHttpRequest) // false
isNativeFunction #1
function isNativeFunction(fn) {
return typeof fn === 'function' &&
/[native code]/.test(Function.prototype.toString.call(fn))
}
window.XMLHttpRequest = function() { /* ... */ }
Function.prototype.toString = function() {
return '[native code]'
}
@vazac
isNativeFunction(XMLHttpRequest) // true
isNativeFunction(XMLHttpRequest) // false
isNativeFunction(XMLHttpRequest) // **true**
(false positive)
isNativeFunction #1
function isNativeFunction(fn) {
return typeof fn === 'function' &&
/[native code]/.test(Function.prototype.toString.call(fn))
}
window.XMLHttpRequest = function() { /* ... */ }
Function.prototype.toString = function() {
return '[native code]'
}
@vazac
Evil Function.prototype.toString
(function() {
const natives = {};
['open', 'send'].forEach(function(methodName) {
natives[methodName] = XMLHttpRequest.prototype[methodName]
XMLHttpRequest.prototype[methodName] = function() {
/* steal all the data here */
return natives[methodName].apply(this, arguments)
}
})
})()
@vazac
Evil Function.prototype.toString
Function.prototype.toString = (function(toString) {
return function () {
let method = this
if (method === XMLHttpRequest.prototype.send)
method = natives['send']
else if (method === XMLHttpRequest.prototype.open)
method = natives['open']
return toString.apply(method, arguments)
}
})(Function.prototype.toString)
@vazac
Detection tactic #1
new XMLHttpRequest()
XMLHttpRequest.prototype.send()
requestAnimationFrame(function() { /* ... */ })
@vazac
Detection tactic #1
debugger; new XMLHttpRequest()
debugger; XMLHttpRequest.prototype.send()
debugger; requestAnimationFrame(function() { /* ... */ })
@vazac
Detection tactic #2
@vazac
const isNativeFunction = (function() {
return function(fn) {
return typeof fn === 'function' &&
/[native code]/.test(getTrustWorthySerializer().call(fn))
}
})()
@vazac
const isNativeFunction = (function() {
return function(fn) {
return typeof fn === 'function' &&
/[native code]/.test(getTrustWorthySerializer().call(fn))
}
})()
@vazac
const isNativeFunction = (function() {
function getTrustWorthySerializer() {
const iframe = document.createElement('iframe')
iframe.src = 'javascript:false'
document.getElementsByTagName('script')[0].parentNode.appendChild(iframe)
const serializer = iframe.contentWindow.Function.prototype.toString
iframe.parentNode.removeChild(iframe)
return serializer
}
return function(fn) {
return typeof fn === 'function' &&
/[native code]/.test(getTrustWorthySerializer().call(fn))
}
})()
@vazac
Detection tactic #3
requestAnimationFrame(function(){
try {
foo.bar()
} catch(e) {
/* inspect e.stack */
}
})
@vazac
Detection tactic #3
// native
new Error ReferenceError: foo is not defined
at bundle.js:21:7
@vazac
Detection tactic #3
// wrapped
new Error ReferenceError: foo is not defined
at bundle.js:21:7
at window.requestAnimationFrame.args.(anonymous function) (hijacker.js:12:18)
// native
new Error ReferenceError: foo is not defined
at bundle.js:21:7
@vazac
Detection tactic #3
// wrapped
new Error ReferenceError: foo is not defined
at bundle.js:21:7
at window.requestAnimationFrame.args.(anonymous function) (hijacker.js:12:18)
// native
new Error ReferenceError: foo is not defined
at bundle.js:21:7
@vazac
Detection tactic #4
(function() {
const httpVerbTrap = {}
httpVerbTrap.toString = function() {
try {
foo.bar()
} catch (e) { /* inspect e.stack */ }
return 'GET'
}
const xhr = new XMLHttpRequest()
xhr.open(httpVerbTrap, '')
})()
@vazac
Detection tactic #4
(function() {
const httpVerbTrap = {}
httpVerbTrap.toString = function() {
try {
foo.bar()
} catch (e) { /* inspect e.stack */ }
return 'GET'
}
const xhr = new XMLHttpRequest()
xhr.open(httpVerbTrap, '')
})()
@vazac
Wrapping up
● Be careful when bringing in third parties
● Code defensively
● Sandbox third parties, if possible
● Freeze the objects that you need to remain native
● Create short lived browser contexts to grab clean natives
● Detect native overrides with traps
@vazac
Tools
● Request Map Generator by @simonhearne - http://requestmap.webperf.tools/
● Detect native overrides bookmarklet - https://github.com/cvazac/detect-native-overrides
● Freeze constructors, methods, and properties - https://github.com/cvazac/freeze.js
@vazac
Thanks!!
Charles Vazac
@vazac

More Related Content

What's hot

Building a js widget
Building a js widgetBuilding a js widget
Building a js widgetTudor Barbu
 
Netvibes UWA workshop at ParisWeb 2007
Netvibes UWA workshop at ParisWeb 2007Netvibes UWA workshop at ParisWeb 2007
Netvibes UWA workshop at ParisWeb 2007Netvibes
 
Plone Interactivity
Plone InteractivityPlone Interactivity
Plone InteractivityEric Steele
 
Creating the interfaces of the future with the APIs of today
Creating the interfaces of the future with the APIs of todayCreating the interfaces of the future with the APIs of today
Creating the interfaces of the future with the APIs of todaygerbille
 
Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013
Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013
Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013Joao Lucas Santana
 
iPhone Appleless Apps
iPhone Appleless AppsiPhone Appleless Apps
iPhone Appleless AppsRemy Sharp
 
Turn your spaghetti code into ravioli with JavaScript modules
Turn your spaghetti code into ravioli with JavaScript modulesTurn your spaghetti code into ravioli with JavaScript modules
Turn your spaghetti code into ravioli with JavaScript modulesjerryorr
 
Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011Chris Alfano
 
jQuery 1.7 Events
jQuery 1.7 EventsjQuery 1.7 Events
jQuery 1.7 Eventsdmethvin
 
Rails 3: Dashing to the Finish
Rails 3: Dashing to the FinishRails 3: Dashing to the Finish
Rails 3: Dashing to the FinishYehuda Katz
 
Introduction to AngularJS For WordPress Developers
Introduction to AngularJS For WordPress DevelopersIntroduction to AngularJS For WordPress Developers
Introduction to AngularJS For WordPress DevelopersCaldera Labs
 
jQuery Presentation to Rails Developers
jQuery Presentation to Rails DevelopersjQuery Presentation to Rails Developers
jQuery Presentation to Rails DevelopersYehuda Katz
 
SproutCore is Awesome - HTML5 Summer DevFest
SproutCore is Awesome - HTML5 Summer DevFestSproutCore is Awesome - HTML5 Summer DevFest
SproutCore is Awesome - HTML5 Summer DevFesttomdale
 
20130528 solution linux_frousseau_nopain_webdev
20130528 solution linux_frousseau_nopain_webdev20130528 solution linux_frousseau_nopain_webdev
20130528 solution linux_frousseau_nopain_webdevFrank Rousseau
 
Modern frontend development with VueJs
Modern frontend development with VueJsModern frontend development with VueJs
Modern frontend development with VueJsTudor Barbu
 
Guia de Sobrevivência JS no mundo Open Source
Guia de Sobrevivência JS no mundo Open SourceGuia de Sobrevivência JS no mundo Open Source
Guia de Sobrevivência JS no mundo Open SourceLeonardo Balter
 
Django の認証処理実装パターン / Django Authentication Patterns
Django の認証処理実装パターン / Django Authentication PatternsDjango の認証処理実装パターン / Django Authentication Patterns
Django の認証処理実装パターン / Django Authentication PatternsMasashi Shibata
 

What's hot (20)

Building a js widget
Building a js widgetBuilding a js widget
Building a js widget
 
Netvibes UWA workshop at ParisWeb 2007
Netvibes UWA workshop at ParisWeb 2007Netvibes UWA workshop at ParisWeb 2007
Netvibes UWA workshop at ParisWeb 2007
 
Plone Interactivity
Plone InteractivityPlone Interactivity
Plone Interactivity
 
Creating the interfaces of the future with the APIs of today
Creating the interfaces of the future with the APIs of todayCreating the interfaces of the future with the APIs of today
Creating the interfaces of the future with the APIs of today
 
สปริงเฟรมเวิร์ค4.1
สปริงเฟรมเวิร์ค4.1สปริงเฟรมเวิร์ค4.1
สปริงเฟรมเวิร์ค4.1
 
Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013
Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013
Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013
 
Sane Async Patterns
Sane Async PatternsSane Async Patterns
Sane Async Patterns
 
iPhone Appleless Apps
iPhone Appleless AppsiPhone Appleless Apps
iPhone Appleless Apps
 
Merb jQuery
Merb jQueryMerb jQuery
Merb jQuery
 
Turn your spaghetti code into ravioli with JavaScript modules
Turn your spaghetti code into ravioli with JavaScript modulesTurn your spaghetti code into ravioli with JavaScript modules
Turn your spaghetti code into ravioli with JavaScript modules
 
Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011
 
jQuery 1.7 Events
jQuery 1.7 EventsjQuery 1.7 Events
jQuery 1.7 Events
 
Rails 3: Dashing to the Finish
Rails 3: Dashing to the FinishRails 3: Dashing to the Finish
Rails 3: Dashing to the Finish
 
Introduction to AngularJS For WordPress Developers
Introduction to AngularJS For WordPress DevelopersIntroduction to AngularJS For WordPress Developers
Introduction to AngularJS For WordPress Developers
 
jQuery Presentation to Rails Developers
jQuery Presentation to Rails DevelopersjQuery Presentation to Rails Developers
jQuery Presentation to Rails Developers
 
SproutCore is Awesome - HTML5 Summer DevFest
SproutCore is Awesome - HTML5 Summer DevFestSproutCore is Awesome - HTML5 Summer DevFest
SproutCore is Awesome - HTML5 Summer DevFest
 
20130528 solution linux_frousseau_nopain_webdev
20130528 solution linux_frousseau_nopain_webdev20130528 solution linux_frousseau_nopain_webdev
20130528 solution linux_frousseau_nopain_webdev
 
Modern frontend development with VueJs
Modern frontend development with VueJsModern frontend development with VueJs
Modern frontend development with VueJs
 
Guia de Sobrevivência JS no mundo Open Source
Guia de Sobrevivência JS no mundo Open SourceGuia de Sobrevivência JS no mundo Open Source
Guia de Sobrevivência JS no mundo Open Source
 
Django の認証処理実装パターン / Django Authentication Patterns
Django の認証処理実装パターン / Django Authentication PatternsDjango の認証処理実装パターン / Django Authentication Patterns
Django の認証処理実装パターン / Django Authentication Patterns
 

Similar to How to identify bad third parties on your page

Private slideshow
Private slideshowPrivate slideshow
Private slideshowsblackman
 
H3 경쟁력있는 웹앱 개발을 위한 모바일 js 프레임웍
H3 경쟁력있는 웹앱 개발을 위한 모바일 js 프레임웍H3 경쟁력있는 웹앱 개발을 위한 모바일 js 프레임웍
H3 경쟁력있는 웹앱 개발을 위한 모바일 js 프레임웍민태 김
 
MeasureCamp IX (London) - 10 JavaScript Concepts for web analysts
MeasureCamp IX (London) - 10 JavaScript Concepts for web analystsMeasureCamp IX (London) - 10 JavaScript Concepts for web analysts
MeasureCamp IX (London) - 10 JavaScript Concepts for web analystsSimo Ahava
 
Service Worker - Reliability bits
Service Worker - Reliability bitsService Worker - Reliability bits
Service Worker - Reliability bitsjungkees
 
Getting the Most Out of jQuery Widgets
Getting the Most Out of jQuery WidgetsGetting the Most Out of jQuery Widgets
Getting the Most Out of jQuery Widgetsvelveeta_512
 
Kakunin E2E framework showcase
Kakunin E2E framework showcaseKakunin E2E framework showcase
Kakunin E2E framework showcaseThe Software House
 
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsFrancois Zaninotto
 
jQuery: Tips, tricks and hints for better development and Performance
jQuery: Tips, tricks and hints for better development and PerformancejQuery: Tips, tricks and hints for better development and Performance
jQuery: Tips, tricks and hints for better development and PerformanceJonas De Smet
 
Some Advanced Tracking in Google Analytics in 5 mins - PhillyJS meet up
Some Advanced Tracking in Google Analytics in 5 mins - PhillyJS meet up Some Advanced Tracking in Google Analytics in 5 mins - PhillyJS meet up
Some Advanced Tracking in Google Analytics in 5 mins - PhillyJS meet up Nico Miceli
 
AnkaraJUG Kasım 2012 - PrimeFaces
AnkaraJUG Kasım 2012 - PrimeFacesAnkaraJUG Kasım 2012 - PrimeFaces
AnkaraJUG Kasım 2012 - PrimeFacesAnkara JUG
 

Similar to How to identify bad third parties on your page (20)

Private slideshow
Private slideshowPrivate slideshow
Private slideshow
 
H3 경쟁력있는 웹앱 개발을 위한 모바일 js 프레임웍
H3 경쟁력있는 웹앱 개발을 위한 모바일 js 프레임웍H3 경쟁력있는 웹앱 개발을 위한 모바일 js 프레임웍
H3 경쟁력있는 웹앱 개발을 위한 모바일 js 프레임웍
 
Django at the Disco
Django at the DiscoDjango at the Disco
Django at the Disco
 
jQuery Best Practice
jQuery Best Practice jQuery Best Practice
jQuery Best Practice
 
MeasureCamp IX (London) - 10 JavaScript Concepts for web analysts
MeasureCamp IX (London) - 10 JavaScript Concepts for web analystsMeasureCamp IX (London) - 10 JavaScript Concepts for web analysts
MeasureCamp IX (London) - 10 JavaScript Concepts for web analysts
 
Clean Javascript
Clean JavascriptClean Javascript
Clean Javascript
 
JS-05-Handlebars.ppt
JS-05-Handlebars.pptJS-05-Handlebars.ppt
JS-05-Handlebars.ppt
 
Service Worker - Reliability bits
Service Worker - Reliability bitsService Worker - Reliability bits
Service Worker - Reliability bits
 
Django at the Disco
Django at the DiscoDjango at the Disco
Django at the Disco
 
Django at the Disco
Django at the DiscoDjango at the Disco
Django at the Disco
 
Django at the Disco
Django at the DiscoDjango at the Disco
Django at the Disco
 
Django at the Disco
Django at the DiscoDjango at the Disco
Django at the Disco
 
G* on GAE/J 挑戦編
G* on GAE/J 挑戦編G* on GAE/J 挑戦編
G* on GAE/J 挑戦編
 
Getting the Most Out of jQuery Widgets
Getting the Most Out of jQuery WidgetsGetting the Most Out of jQuery Widgets
Getting the Most Out of jQuery Widgets
 
Kakunin E2E framework showcase
Kakunin E2E framework showcaseKakunin E2E framework showcase
Kakunin E2E framework showcase
 
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
 
jQuery: Tips, tricks and hints for better development and Performance
jQuery: Tips, tricks and hints for better development and PerformancejQuery: Tips, tricks and hints for better development and Performance
jQuery: Tips, tricks and hints for better development and Performance
 
Some Advanced Tracking in Google Analytics in 5 mins - PhillyJS meet up
Some Advanced Tracking in Google Analytics in 5 mins - PhillyJS meet up Some Advanced Tracking in Google Analytics in 5 mins - PhillyJS meet up
Some Advanced Tracking in Google Analytics in 5 mins - PhillyJS meet up
 
jQuery: Events, Animation, Ajax
jQuery: Events, Animation, AjaxjQuery: Events, Animation, Ajax
jQuery: Events, Animation, Ajax
 
AnkaraJUG Kasım 2012 - PrimeFaces
AnkaraJUG Kasım 2012 - PrimeFacesAnkaraJUG Kasım 2012 - PrimeFaces
AnkaraJUG Kasım 2012 - PrimeFaces
 

Recently uploaded

How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Alan Dix
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphNeo4j
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
Artificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning eraArtificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning eraDeakin University
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptxLBM Solutions
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersThousandEyes
 

Recently uploaded (20)

How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
Artificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning eraArtificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning era
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptx
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
 

How to identify bad third parties on your page