Description
All modern browsers block JavaScript from accessing httpOnly
cookies; and Chrome blocks JavaScript from accessing the nonce
attribute in <script nonce="abc123">
(details).
Would it be possible for websites to also block (potentially malicious) JavaScript from accessing other values from the DOM?
For example, I'd like to stop any JavaScript/CSS from accessing the CSRF token from a hidden input field (used in addition to SameSite cookies).
Two features I'd find useful would include:
- An attribute on the
<input>
so it's value (or the element) can't be accessed via the DOM, or via CSS selectors. - A header to block XMLHttpRequest (or fetch) from accessing the content from a same-site request.
The first might be possible to introduce via the inert attribute, which is currently being specced as a simple flag to stop interaction events, text search, selecting text, and hiding from assistive technology.
The second could be as simple as recognising Access-Control-Allow-Origin: 'none'
to stop all origins from being allowed to read the contents of the response (effectively causing same-site requests to be treated like a cross-origin request).
In Google Chrome, this example shows how the <script nonce="abc123">
can't be accessed, whereas the hidden input field named "csrf" can be.
Content-Security-Policy:
default-src 'none';
script-src 'nonce-123js';
style-src 'nonce-123css';
connect-src 'self';
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Sensitive Page</title>
</head>
<body>
<form action="./?id=5" method="post">
<input type="hidden" name="csrf" value="123csrf" />
<input type="submit" value="Delete" />
</form>
<script nonce="123js">
var script = document.getElementsByTagName('script')[0],
input = document.getElementsByTagName('input')[0];
console.log(script.getAttribute('nonce'));
console.log(script.outerHTML); // Returns <script nonce="">...
console.log(script.nonce); // Works, but not needed for this case.
console.log(input.getAttribute('value'));
fetch(window.location).then(function(response) {
return response.text();
}).then(function(text) {
console.log(text);
});
</script>
<style nonce="123css">
input[value^="123"] + input {
border: 1px solid red;
}
</style>
</body>
</html>