Can you hack it?

24 views
Skip to first unread message

Alan Karp

unread,
May 24, 2023, 6:12:10 PM5/24/23
to <friam@googlegroups.com>
When I submit SitePassword to the Firefox store, I get a warning about document.write(). I need it because Safari doesn't support browser.tabs.create(), which I use to create the page when you click Download Settings.  Is there a threat?

When you click the Download Settings button on Safari, you download a table that looks like

image.png
The Domain Name links contain the settings, which include values provided by the user, specifically the site name, user name, and special characters.  Clicking on the domain name opens sitepassword.info with the settings for the site filled in.  All settings are inserted into the sitepassword.info form with element.value, which I believe treats the input as text.  Neither the page containing the table nor sitepassword.info interact with other pages or a database, but sitepassword.info uses localStorage if you save your settings.

Normally, you are the only one who will see this page, so any attack would be against yourself, but what if you send the page to someone else.  Can you construct input values that could do some harm?  I've tried and failed.

--------------
Alan Karp

Douglas Crockford

unread,
May 25, 2023, 8:39:55 AM5/25/23
to friam
Historically, document.write is one of the most dangerous capabilities provided by the browser. I have been advocating for its elimination for decades It may be that because your Download Settings page is not defending a web site that you can get away with it. For you the risk is that someone will do a View Source and see that a program that claims to be secure is using document.write, which would be at least ironic, if not extremely suspicious.

Everything that you can do with document.write can be done with safer methods. For example, you can use createTextNode and replaceChild to do the same thing without raising any alarms.

Alan Karp

unread,
May 25, 2023, 5:53:49 PM5/25/23
to fr...@googlegroups.com
In Chrome and Firefox, I use tabs.create, but Safari doesn't support it.  Safari doesn't support the old downloads API or the new file system API, either.  So far, document.write is the only way I've been able to implement Download Settings on Safari.  A quick look should show that it's safe.

        let w = window.open();

        w.document.open();

        w.document.write(sd); // sd is a string that I construct from the settings for each site

        w.document.close();


Anything written goes to a brand new window.  I don't think there's an attack against it.  (A separate issue is that the document has links that include user-provided data in the query string that is used by sitepassword.info.  However, those values are only used in element.value =.  Again, I don't think there are any attacks.  Even if there were, I don't know how a successful attacker could cause harm to anyone else.)

That being said, the fact that a text search will turn up document.write will likely turn off a security aware user.  If you know of another way to write a file, download a document of my creation, or open a tab or web page showing the contents that I can SaveAs, let me know.  (Chrome won't let me do a SaveAs on a new window created with a data URI, but it will for a newly created tab.  Explain that to me.)

--------------
Alan Karp


--
You received this message because you are subscribed to the Google Groups "friam" group.
To unsubscribe from this group and stop receiving emails from it, send an email to friam+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/friam/314f12d9-23c7-4fcc-88bb-e32a5d3bdae3n%40googlegroups.com.

Mike Stay

unread,
May 25, 2023, 6:35:55 PM5/25/23
to fr...@googlegroups.com
On Thu, May 25, 2023 at 3:53 PM Alan Karp <alan...@gmail.com> wrote:
>
> In Chrome and Firefox, I use tabs.create, but Safari doesn't support it. Safari doesn't support the old downloads API or the new file system API, either. So far, document.write is the only way I've been able to implement Download Settings on Safari. A quick look should show that it's safe.
>
> let w = window.open();
>
> w.document.open();
>
> w.document.write(sd); // sd is a string that I construct from the settings for each site
>
> w.document.close();

I still don't see why you need it. What's in sd that you can't create
using w.document.createElement, appendChild, etc?
--
Mike Stay - meta...@gmail.com
https://math.ucr.edu/~mike
https://reperiendi.wordpress.com

Alan Karp

unread,
May 25, 2023, 7:20:01 PM5/25/23
to fr...@googlegroups.com
On Thu, May 25, 2023 at 3:35 PM Mike Stay <meta...@gmail.com> wrote:

I still don't see why you need it.  What's in sd that you can't create
using w.document.createElement, appendChild, etc?

Here's just a snippet of the construction of sd.

sd += "<th>Specials</th>";
sd += "<th>Code for User Provided Password</th>";
sd += "</tr>";
for (var i = 0; i < sorted.length; i++) {
var domainname = sorted[i];
var sitename = domainnames[sorted[i]];
var s = sitenames[sitename];
var bkmk = JSON.stringify(s);
sd += "<tr>";
sd += "<td><a title='Right click to copy bookmark' href=" + webpage + "?bkmk=ssp://" + bkmk + ">" + domainname + "</a></td>";
sd += "<td><pre>" + s.sitename + "</pre></td>";
sd += "<td><pre>" + s.username + "</pre></td>";
sd += "<td><pre>" + s.pwlength + "</pre></td>";

Adding all those elements will be a pain.  To make matters worse, I only need to do that for Safari.  I can make things work just fine with the string in Chrome and Firefox.  One approach that might work is to use a template element, but I'd need template.innerHTML, which has many of the same risks.

--------------
Alan Karp


--
You received this message because you are subscribed to the Google Groups "friam" group.
To unsubscribe from this group and stop receiving emails from it, send an email to friam+un...@googlegroups.com.

Kris Kowal

unread,
May 25, 2023, 7:33:57 PM5/25/23
to fr...@googlegroups.com
I’ve become increasingly resigned to hand-rolling DOM subtree creation. Just to give you a taste of the hell of my own choosing:


Join me. The water is warm!

Mike Stay

unread,
May 25, 2023, 9:10:43 PM5/25/23
to fr...@googlegroups.com
There are existing tools like https://github.com/Damian96/html-to-dom
that take html as input, parse it, and generate dom calls, effectively
giving you the same API as document.write().
> To view this discussion on the web visit https://groups.google.com/d/msgid/friam/CANpA1Z2SGwMwn9n4YMiGX2T%2B5Jz8We0L28SmOynU6F%3Da2cKnLg%40mail.gmail.com.

Kevin Reid

unread,
May 25, 2023, 9:16:45 PM5/25/23
to fr...@googlegroups.com
On Thu, May 25, 2023 at 4:20 PM Alan Karp <alan...@gmail.com> wrote:
Adding all those elements will be a pain.  To make matters worse, I only need to do that for Safari.  I can make things work just fine with the string in Chrome and Firefox.  One approach that might work is to use a template element, but I'd need template.innerHTML, which has many of the same risks.

If you can avoid document.write by using .innerHTML, even if there is no difference in restrictions, I'd recommend doing that. document.write has some quite funky semantics due to its original role of injecting text into the parser as the document is still being loaded.

๏̯͡๏ Jasvir Nagra

unread,
May 25, 2023, 9:17:08 PM5/25/23
to fr...@googlegroups.com
FYI that specific tool does "html parsing" by setting innerHTML admittedly on an unattached doc but that still results in some browsers fetching resources and turning event handlers into code.


-- 
Jasvir Nagra


Alan Karp

unread,
May 25, 2023, 9:44:10 PM5/25/23
to fr...@googlegroups.com
On Thu, May 25, 2023 at 6:10 PM Mike Stay <meta...@gmail.com> wrote:
There are existing tools like https://github.com/Damian96/html-to-dom
that take html as input, parse it, and generate dom calls, effectively
giving you the same API as document.write().

I prefer to avoid the dependency.   

--------------
Alan Karp


Douglas Crockford

unread,
May 26, 2023, 9:59:34 AM5/26/23
to friam
A safer practice than catenation is node construction. You make a <td> node with document.createElement("td"). [https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement]

You then append text to it.

You make a <tr> node with  document.createElement("td") and append the data nodes to it.
You make a <tbody> node with  document.createElement("tbody") and append the row nodes to it.
You make a <table> node with  document.createElement("table") and append the body node to it.

You go to document.body and remove all the children.
You append the table that you made.

It is only slightly more effort than string concatenation, and a whole lot safer. Anyone looking at your code will think that this guy knows what he's doing.

Alan Karp

unread,
May 26, 2023, 12:17:10 PM5/26/23
to fr...@googlegroups.com
I know how to do it, and I might have done it that way had I built the first version for Safari.  Now it would be a tedious task.  My plan right now is to build the document the way you suggest from the string representation if I can't find a simpler workaround for Safari.

--------------
Alan Karp


Douglas Crockford

unread,
May 26, 2023, 12:37:13 PM5/26/23
to friam

    function html(tag, ...nodes) {
        const node = document.createElement(tag);
        node.append(...nodes);
        return node;
    }

    let rows = [
        html("tr", html("td", "Moe"), html("td", "Howard")),
        html("tr", html("td", "Curly"), html("td", "Howard")),
        html("tr", html("td", "Larry"), html("td", "Fine"))
    ];


    document.getElementById("output").append(html("table", html("tbody", ...rows)));
Reply all
Reply to author
Forward
0 new messages