Skip to content
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

HTTPS Upgrades Test Page #15

Merged
merged 29 commits into from
Dec 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a3a2915
Referrer trimming - start
kdzwinel Dec 11, 2020
fcf54e5
Show referrers in the redirect page for a second there.
kdzwinel Dec 11, 2020
78e45c3
Referrer trimming v2
kdzwinel Dec 11, 2020
dd5666d
Cache js referer on page load.
kdzwinel Dec 11, 2020
105c5ee
Add warning about redirects + make it work on glitch.
kdzwinel Dec 11, 2020
a061324
Fix /come-back page for safari.
kdzwinel Dec 14, 2020
c30bc84
Add iframe tests, group duplicated code into functions.
kdzwinel Dec 14, 2020
7142bf3
2s -> 1s waiting time for navigations - referrer-trimming
kdzwinel Dec 14, 2020
410b754
Fix cross-origin communication issue
kdzwinel Dec 14, 2020
57afb29
Missing semicolon
kdzwinel Dec 14, 2020
bc775b8
Make test frames 10x10px.
kdzwinel Dec 14, 2020
dbac404
Fix how we store/clear localStorage partial results.
kdzwinel Dec 14, 2020
ed2b17c
Drop unnecessary console.log
kdzwinel Dec 14, 2020
a48abe6
Fix for when header is not set
kdzwinel Dec 15, 2020
3834ee1
Cosmetic change undefined->''
kdzwinel Dec 15, 2020
0516cfd
HTTPS upgrades - first batch
kdzwinel Dec 16, 2020
8c0ed4d
Hook up test urls.
kdzwinel Dec 16, 2020
3e744f7
Fix postMessage and frame. Add websocket.
kdzwinel Dec 16, 2020
4fa7baa
fix opener/parent issue + websocket cleanup
kdzwinel Dec 16, 2020
e170507
we don't get info about navigation load - we have to pull
kdzwinel Dec 16, 2020
5c0452e
Extract test domain to a constant.
kdzwinel Dec 16, 2020
298d135
Add additional info to https-upgrades.
kdzwinel Dec 16, 2020
1132ac3
Hardcode paths to glitch deployment.
kdzwinel Dec 16, 2020
293c32e
Add note in fingerprinting tests about https being a requirement.
kdzwinel Dec 16, 2020
aaf55ba
fix a typo in url of test domain
kdzwinel Dec 16, 2020
31b8382
Merge remote-tracking branch 'upstream/gh-pages' into gh-pages
kdzwinel Dec 16, 2020
2d780c4
Don't include the TEMPLATE folder right now.
kdzwinel Dec 16, 2020
8feb2e9
Color values.
kdzwinel Dec 16, 2020
1530a02
focus doesn't really work in this scenario
kdzwinel Dec 16, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,11 @@ <h2>Security</h2>

<h2>Privacy Protections Tests</h2>
<ul>
<li><a href="./privacy-protections/request-blocking/">Request blocking</a></li>
<li><a href='./privacy-protections/fingerprinting/'>Fingerprinting</a></li>
<li><a href='./privacy-protections/storage-blocking/'>Storage blocking</a></li>
<li><a href='./privacy-protections/referrer-trimming/'>Referrer trimming</a></li>
<li><a href='https://privacy-test-pages.glitch.me/privacy-protections/request-blocking/'>Request blocking</a></li>
<li><a href='https://privacy-test-pages.glitch.me/privacy-protections/fingerprinting/'>Fingerprinting</a></li>
<li><a href='https://privacy-test-pages.glitch.me/privacy-protections/storage-blocking/'>Storage blocking</a></li>
<li><a href='https://privacy-test-pages.glitch.me/privacy-protections/referrer-trimming/'>Referrer trimming</a></li>
<li><a href='http://privacy-test-pages.glitch.me/privacy-protections/https-upgrades/'>HTTPS upgrades</a></li>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of those pages don't really work on github pages, which might be confusing, so I hardcoded full glitch urls.

</ul>

</body>
Expand Down
7 changes: 4 additions & 3 deletions privacy-protections/fingerprinting/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@
<link href='./style.css' rel='stylesheet'></link>
</head>
<body>
<p><a href="../../">[Home]</a> ↣ <a href="../">[Privacy Protections Tests]</a></p>
<p><a href="../../">[Home]</a> ↣ <a href="../">[Privacy Protections Tests]</a> ↣ <strong>[Fingerprinting Test Page]</strong></p>

<p>This page collects various datapoints from your browser that can be used for fingerprinting.</p>
<p>⚠️ Please note that: </p>
<ul>
<li>not all of the properties listed here have to be modified to succesfully prevent fingerprining,</li>
<li>some properties may change randomly, depending on the brower, on every page reload or test run,</li>
<li>some data is duplicated, but it's retrieved using different methods.</li>
<li>depending on the brower some properties may change randomly on every page reload or test run,</li>
<li>some data is duplicated, but it's retrieved using different methods,</li>
<li>this page has to be loaded over https for all tests to work correctly (some APIs are not available over http).</li>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since glitch is supporting both http and https I added a note that fingerprinting page should be loaded over https.

</ul>

<p><button id='start'>Start the test</button></p>
Expand Down
23 changes: 23 additions & 0 deletions privacy-protections/https-upgrades/frame.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>iframe HTTPS Upgrade Test</title>
</head>
<body>
<script>
const onMessage = msg => {
if (msg.data.action && msg.data.action === 'url') {
if (window.opener) {
window.opener.postMessage({url: document.location.href, type: msg.data.type}, '*');
} else if (window.parent) {
window.parent.postMessage({url: document.location.href, type: msg.data.type}, '*');
}
}
};
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this page returns current url to either parent url (iframe scenario) or opener (window.open scenario).


window.addEventListener('message', onMessage);
</script>
</body>
</html>
29 changes: 29 additions & 0 deletions privacy-protections/https-upgrades/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HTTPS upgrades test page</title>

<script src='./main.js' defer></script>
<link href='./style.css' rel='stylesheet'></link>
</head>
<body>
<p><a href="../../">[Home]</a> ↣ <a href="../">[Privacy Protections Tests]</a> ↣ <strong>[HTTPS Upgrades Test Page]</strong></p>

<p>This page will test if requests and navigations to http pages get upgraded to https.</p>
<p>To test your https upgrading solution please add <storng>good.third-party.site</storng> domain to your upgrade list.</p>
<p>⚠️ Those tests will only work if this page is loaded over <strong>http</strong> (otherwise mixed content will be blocked).</p>

<p><button id='start'>Start test</button></p>

<details id='tests' hidden>
<summary id='tests-summary'></summary>
<ul id='tests-details'>
</ul>
</details>

<p><button id='download' disabled>Download the result</button></p>

</body>
</html>
195 changes: 195 additions & 0 deletions privacy-protections/https-upgrades/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
const startButton = document.querySelector('#start');
const downloadButton = document.querySelector('#download');

const testsDiv = document.querySelector('#tests');
const testsSummaryDiv = document.querySelector('#tests-summary');
const testsDetailsDiv = document.querySelector('#tests-details');

const TEST_DOMAIN = 'good.third-party.site';

const tests = [
{
id: 'upgrade-navigation',
run: () => {
let resolve, reject;
const promise = new Promise((res, rej) => {resolve = res; reject = rej});
const otherWindow = window.open(`http://${TEST_DOMAIN}/privacy-protections/https-upgrades/frame.html`);

const interval = setInterval(() => {
otherWindow.postMessage({action: 'url', type: 'navigation'}, `http://${TEST_DOMAIN}/`);
otherWindow.postMessage({action: 'url', type: 'navigation'}, `https://${TEST_DOMAIN}/`);
}, 500);

function onMessage(m) {
if (m.data && m.data.type === 'navigation') {
clearInterval(interval);
otherWindow.close();
window.removeEventListener('message', onMessage);
resolve(m.data.url);
}
}

window.addEventListener('message', onMessage);

return promise;
}
},
{
id: 'upgrade-iframe',
run: () => {
let resolve, reject;
const promise = new Promise((res, rej) => {resolve = res; reject = rej});

const iframe = document.createElement('iframe');

iframe.addEventListener('load', i => {
iframe.contentWindow.postMessage({action: 'url', type: 'frame'}, `http://${TEST_DOMAIN}/`);
iframe.contentWindow.postMessage({action: 'url', type: 'frame'}, `https://${TEST_DOMAIN}/`);
});

iframe.src = `http://${TEST_DOMAIN}/privacy-protections/https-upgrades/frame.html`;

document.body.appendChild(iframe);

function onMessage(m) {
if (m.data && m.data.type === 'frame') {
window.removeEventListener('message', onMessage);
document.body.removeChild(iframe);
resolve(m.data.url);
}
}

window.addEventListener('message', onMessage);

return promise;
}
},
{
id: 'upgrade-subrequest',
run: () => {
return fetch(`http://${TEST_DOMAIN}/reflect-headers`)
.then(r => r.json())
.then(data => data.url);
}
},
{
id: 'upgrade-websocket',
run: () => {
let resolve, reject;
const promise = new Promise((res, rej) => {resolve = res; reject = rej});

const websocketUrl = `ws://${TEST_DOMAIN}/block-me/web-socket`;
const socket = new WebSocket(websocketUrl);
socket.addEventListener('message', () => {
resolve(socket.url);
});

return promise;
}
}
];

// object that contains results of all tests
const results = {
page: 'https-upgrades',
date: null,
results: []
};

function resultToHTML(data) {
if (Array.isArray(data)) {
return `<ul>${data.map(r => `<li>${r.test} - ${r.result}</li>`).join('')}</ul>`;
} else if (data) {
return JSON.stringify(data, null, 2);
}

return null;
}

/**
* Test runner
*/
function runTests() {
startButton.setAttribute('disabled', 'disabled');
downloadButton.removeAttribute('disabled');
testsDiv.removeAttribute('hidden');

results.results.length = 0;
results.date = (new Date()).toUTCString();
let all = 0;
let failed = 0;

testsDetailsDiv.innerHTML = '';

function updateSummary() {
testsSummaryDiv.innerText = `Performed ${all} tests${failed > 0 ? ` (${failed} failed)` : ''}. Click for details.`;
}

for (const test of tests) {
const resultObj = {
id: test.id,
value: null
};
results.results.push(resultObj);

const li = document.createElement('li');
li.id = `test-${test.id.replace(' ', '-')}`;
li.innerHTML = `${test.id} - <span class='value'>…</span>`;
const valueSpan = li.querySelector('.value');

testsDetailsDiv.appendChild(li);

try {
const result = test.run();

if (result instanceof Promise) {
result
.then(data => {
valueSpan.innerHTML = resultToHTML(data);
resultObj.value = data || null;
})
.catch(e => {
failed++;
valueSpan.innerHTML = `❌ error thrown ("${e.message ? e.message : e}")`;
updateSummary();
});
} else {
valueSpan.innerHTML = resultToHTML(data);;
resultObj.value = result || null;
}
} catch(e) {
failed++;
valueSpan.innerHTML = `❌ error thrown ("${e.message ? e.message : e}")`;
}

all++;
}

updateSummary();

startButton.removeAttribute('disabled');
}

function downloadTheResults() {
const data = JSON.stringify(results, null, 2);
const a = document.createElement('a');
const url = window.URL.createObjectURL(new Blob([data], {type: 'application/json'}));
a.href = url;
a.download = 'fingerprinting-results.json';

document.body.appendChild(a);
a.click();

window.URL.revokeObjectURL(url);
a.remove();
}

downloadButton.addEventListener('click', () => downloadTheResults());

// run tests if button was clicked or…
startButton.addEventListener('click', () => runTests());

// if url query is '?run'
if (document.location.search === '?run') {
runTests();
}
7 changes: 7 additions & 0 deletions privacy-protections/https-upgrades/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
* {
box-sizing: border-box;
}

.value {
color: gray;
}
11 changes: 6 additions & 5 deletions privacy-protections/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@
<title>Privacy Protections Tests</title>
</head>
<body>
<p><a href="../">[Home]</a></p>
<p><a href="../">[Home]</a> ↣ <strong>[Privacy Protections Tests]</strong></p>

<h1>Privacy Protections Tests</h1>

<ul>
<li><a href='./request-blocking/'>Request blocking</a></li>
<li><a href='./fingerprinting/'>Fingerprinting</a></li>
<li><a href='./storage-blocking/'>Storage blocking</a></li>
<li><a href='./referrer-trimming/'>Referrer trimming</a></li>
<li><a href='https://privacy-test-pages.glitch.me/privacy-protections/request-blocking/'>Request blocking</a></li>
<li><a href='https://privacy-test-pages.glitch.me/privacy-protections/fingerprinting/'>Fingerprinting</a></li>
<li><a href='https://privacy-test-pages.glitch.me/privacy-protections/storage-blocking/'>Storage blocking</a></li>
<li><a href='https://privacy-test-pages.glitch.me/privacy-protections/referrer-trimming/'>Referrer trimming</a></li>
<li><a href='http://privacy-test-pages.glitch.me/privacy-protections/https-upgrades/'>HTTPS upgrades</a></li>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto - hardcoded urls

</ul>

</body>
Expand Down
2 changes: 1 addition & 1 deletion privacy-protections/referrer-trimming/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<link href='./style.css' rel='stylesheet'></link>
</head>
<body>
<p><a href="../../">[Home]</a> ↣ <a href="../">[Privacy Protections Tests]</a></p>
<p><a href="../../">[Home]</a> ↣ <a href="../">[Privacy Protections Tests]</a> ↣ <strong>[Referrer Trimming Test Page]</strong></p>

<p>This page will test if, and how, referrer header value changes in various scenarios.</p>
<p>⚠️ Please note that the page will redirect couple of times after you start the test. This is expected, please wait till all the tests finish.</p>
Expand Down
2 changes: 1 addition & 1 deletion privacy-protections/referrer-trimming/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function generateNavigationTest(url) {

if (localStorage[key]) {// test already finished before
return JSON.parse(localStorage[key]);
} else if(currentURL.searchParams.get('js')) {// test finished now
} else if(currentURL.searchParams.get('js') !== null) {// test finished now
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unrelated fix for referrer trimming - we have to test for null specifically because Brave, in certain scenarios trims referrer to an empty string.

const result = [
{
test: 'js',
Expand Down
2 changes: 1 addition & 1 deletion privacy-protections/request-blocking/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<link href='./style.css' rel='stylesheet'></link>
</head>
<body>
<p><a href="../../">[Home]</a> ↣ <a href="../">[Privacy Protections Tests]</a></p>
<p><a href="../../">[Home]</a> ↣ <a href="../">[Privacy Protections Tests]</a> ↣ <strong>[Request Blocking Test Page]</strong></p>

<p>This page tests if different types of requests, made using various browser mechanisms, are getting blocked.</p>
<p>To test your request blocking solution please add <storng>bad.third-party.site</storng> domain to your blocklist.</p>
Expand Down
2 changes: 1 addition & 1 deletion privacy-protections/storage-blocking/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<link href='./style.css' rel='stylesheet'></link>
</head>
<body>
<p><a href="../../">[Home]</a> ↣ <a href="../">[Privacy Protections Tests]</a></p>
<p><a href="../../">[Home]</a> ↣ <a href="../">[Privacy Protections Tests]</a> ↣ <strong>[Storage Blocking Test Page]</strong></p>

<p>This page will try to store, and then retrieve, a random number using various storage mechanisms in the browser.</p>

Expand Down
17 changes: 13 additions & 4 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@ const express = require('express');
const ws = require('ws');
const app = express();
const port = process.env.PORT || 3000;
const url = require('url');

function fullUrl(req) {
return url.format({
protocol: req.protocol,
host: req.get('host'),
pathname: req.originalUrl
});
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this returns full url that was requested (we need that to see if the protocol was http or https)

}

// start server
const listener = app.listen(port, () => {
Expand Down Expand Up @@ -66,13 +75,13 @@ app.post('/block-me/csp', (req, res) => {
return res.sendStatus(200);
});

// reflects request headers back
// reflects request headers and request url back
app.get('/reflect-headers', (req, res) => {
res.set('Access-Control-Allow-Origin', req.headers.origin || '*');
res.set('Access-Control-Allow-Credentials', 'true');
res.set('Timing-Allow-Origin', '*');

return res.json({headers: req.headers});
return res.json({url: fullUrl(req), headers: req.headers});
});

// sets a cookie with provided value
Expand Down Expand Up @@ -108,9 +117,9 @@ app.get('/come-back', (req, res) => {
<body>
<script>
const jsReferrer = document.referrer;
document.body.innerHTML += '<p>header: <strong>${req.headers.referer}</strong></p><p>js: <strong>' + jsReferrer + '</strong></p>';
document.body.innerHTML += '<p>header: <strong>${req.headers.referer || ''}</strong></p><p>js: <strong>' + jsReferrer + '</strong></p>';
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unrelated referrer clean up - for Brave referrer is sometimes undefined in which scenarios we want to return '' instead 'undefined'

setTimeout(() => {
location.href = 'https://privacy-test-pages.glitch.me/privacy-protections/referrer-trimming/?run&header=${req.headers.referer}&js=' + jsReferrer;
location.href = 'https://privacy-test-pages.glitch.me/privacy-protections/referrer-trimming/?run&header=${req.headers.referer || ''}&js=' + jsReferrer;
}, 1000);
</script>
</body>
Expand Down