Skip to content

Restricting JavaScript from accessing secrets #536

Open
@craigfrancis

Description

@craigfrancis

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:

  1. An attribute on the <input> so it's value (or the element) can't be accessed via the DOM, or via CSS selectors.
  2. 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>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions