Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss
Groups keyboard shortcuts have been updated
Dismiss
See shortcuts

onsubmit mehrfach auslösen

4 views
Skip to first unread message

Stefan Froehlich

unread,
Feb 3, 2022, 9:14:49 AM2/3/22
to
Vor Jahrzehnten (buchstäblich zu verstehen) hatte ich eine Reihe von
Formularen mit:

#v+
<form onsubmit="return onesubmitonly();">
</form>
#v-

versehen, um mehrfaches Triggern der gleichen, etwas länger
dauernden Aktion zu verhindern, wobei onesubmitonly() recht simpel
gehalten ist:

#v+
var isSubmitted;
function onesubmitonly() {
if (isSubmitted) return false;
isSubmitted = true;
return true;
}
#v-

Das hat so gut funktioniert, dass ich vollkommen darauf vergessen
hatte, bis vor kurzem eine verschärfte CSP-Policy die Inline-Handler
deaktiviert hat.

Ein erster Versuch zur Neugestaltung sieht so aus:

#v+
<form id="61fbe1414dff6">
</form>
<script type="text/javascript" nonce="xxxxx">
document.getElementById("61fbe1414dff6").addEventListener('submit',
function(e) { return onesubmitonly(); });
</script>
#v-

Für den ersten Klick funktioniert das auch, das Skript wird
beim Klick auf den Submit-Button aufgerufen (nonce, id und
Funktionsnamen sind also wohl korrekt). Dummerweise gilt das aber
nicht für alle weiteren Klicks, wenn der Benutzer nur schnell genug
ist - die gehen weiterhin durch.

Was habe ich da schon wieder grundsätzliches übersehen?

Servus,
Stefan

--
http://kontaktinser.at/ - die kostenlose Kontaktboerse fuer Oesterreich
Offizieller Erstbesucher(TM) von mmeike

Stefan - die Verkündigung des prächtigen Träumens.</b
(Sloganizer)

Stefan Reuther

unread,
Feb 3, 2022, 11:33:29 AM2/3/22
to
Am 03.02.2022 um 15:14 schrieb Stefan Froehlich:
> #v+
> <form id="61fbe1414dff6">
> </form>
> <script type="text/javascript" nonce="xxxxx">
> document.getElementById("61fbe1414dff6").addEventListener('submit',
> function(e) { return onesubmitonly(); });
> </script>
> #v-

Wo ist denn 'onesubmitonly' in der Version definiert?

(Wenn ich das richtig sehe, muss das nonce auch noch vom Server in einem
Header ausgeliefert werden? Kann der nicht gleich einen "CSP: mir egal"
Header ausliefern, um alle inline-Skripte freizuschalten?)

> Was habe ich da schon wieder grundsätzliches übersehen?

Ich würde das Skript in eine separate Datei packen, dann

<form class="one-only">

und

document.addEventListener('DOMContentLoaded', function() {
var es = document.getElementsByClassName('one-only');
for (var i = 0; i < es.length; ++i) {
es[i].addEventListener(...);
}
});


Stefan

Stefan Froehlich

unread,
Feb 3, 2022, 1:29:03 PM2/3/22
to
On Thu, 03 Feb 2022 17:23:39 Stefan Reuther wrote:
> Am 03.02.2022 um 15:14 schrieb Stefan Froehlich:
>> #v+
>> <form id="61fbe1414dff6">
>> </form>
>> <script type="text/javascript" nonce="xxxxx">
>> document.getElementById("61fbe1414dff6").addEventListener('submit',
>> function(e) { return onesubmitonly(); });
>> </script>
>> #v-
>
> Wo ist denn 'onesubmitonly' in der Version definiert?

In einem externen File.

> (Wenn ich das richtig sehe, muss das nonce auch noch vom Server in
> einem Header ausgeliefert werden? Kann der nicht gleich einen
> "CSP: mir egal" Header ausliefern, um alle inline-Skripte
> freizuschalten?)

Könnte er natürlich, aber damit würde sich der Kreis schließen: Ich
mache den Kopfstand deshalb, weil ein Security-Consultant das
onsubmit="" als Böse[TM] markiert hat, und sich in solchen Fällen
immer der größere durchsetzt - das bin nicht ich.

> Ich würde das Skript in eine separate Datei packen, dann
>
> <form class="one-only">
>
> und
>
> document.addEventListener('DOMContentLoaded', function() {
> var es = document.getElementsByClassName('one-only');
> for (var i = 0; i < es.length; ++i) {
> es[i].addEventListener(...);
> }
> });

Naja, ob ich es jetzt über die Klasse oder über die Id referenziere,
ist dann auch schon egal (letzteres ist ein Akt der Bequemlichkeit,
mein Framework tut das weitgehend automatisch für mich).

Ich hab jetzt Minimalbeispiele auf meinen Server gestellt:

Neu: <http://froehlich.priv.at/test.php> funktioniert nicht
Alt: <http://froehlich.priv.at/test2.php> funktioniert

Der Button tut nichts, ausser die Seite noch einmal zu laden, und
deren einziger Zweck ist eine Verzögerung von 1 Sekunde; den Effekt
triggert man durch sehr rasches, mehrfaches Anklicken des Buttons.
Ohne Zugriff auf das Serverlog ist der Unterschied aber eher nur im
"Network"-Tab des Debuggers sichtbar.

Das kann eigentlich nur ein sehr banales Brett vor meinem Kopf sein,
aber ich komme nicht drauf...

Servus,
Stefan

--
http://kontaktinser.at/ - die kostenlose Kontaktboerse fuer Oesterreich
Offizieller Erstbesucher(TM) von mmeike

Stefan - der blödste Aufreisser, den es je geben wird.
(Sloganizer)

Stefan Reuther

unread,
Feb 4, 2022, 10:58:20 AM2/4/22
to
Am 03.02.2022 um 19:29 schrieb Stefan Froehlich:
> On Thu, 03 Feb 2022 17:23:39 Stefan Reuther wrote:
>> Am 03.02.2022 um 15:14 schrieb Stefan Froehlich:
>>> #v+
>>> <form id="61fbe1414dff6">
>>> </form>
>>> <script type="text/javascript" nonce="xxxxx">
>>> document.getElementById("61fbe1414dff6").addEventListener('submit',
>>> function(e) { return onesubmitonly(); });
>>> </script>
>>> #v-
>>
>> Wo ist denn 'onesubmitonly' in der Version definiert?
>
> In einem externen File.

ok.

>> (Wenn ich das richtig sehe, muss das nonce auch noch vom Server in
>> einem Header ausgeliefert werden? Kann der nicht gleich einen
>> "CSP: mir egal" Header ausliefern, um alle inline-Skripte
>> freizuschalten?)
>
> Könnte er natürlich, aber damit würde sich der Kreis schließen: Ich
> mache den Kopfstand deshalb, weil ein Security-Consultant das
> onsubmit="" als Böse[TM] markiert hat, und sich in solchen Fällen
> immer der größere durchsetzt - das bin nicht ich.

Und der hat nicht angemeckert, dass man Doppel-Submit eigentlich auf dem
Server filtern sollte? :-)

>> Ich würde das Skript in eine separate Datei packen, dann
>>
>> <form class="one-only">
>>
>> und
>>
>> document.addEventListener('DOMContentLoaded', function() {
>> var es = document.getElementsByClassName('one-only');
>> for (var i = 0; i < es.length; ++i) {
>> es[i].addEventListener(...);
>> }
>> });
>
> Naja, ob ich es jetzt über die Klasse oder über die Id referenziere,
> ist dann auch schon egal (letzteres ist ein Akt der Bequemlichkeit,
> mein Framework tut das weitgehend automatisch für mich).

Vorteil der Suche über den Klassennamen ist, dass man das
Spezialverhalten automatisch überall bekommt, wo die Klasse benutzt
wird. Man kann also einfach ins HTML ein solches Formular schreiben, und
das Javascript greift sich das automatisch. Wenn du ein Framework hast,
das die IDs passend vergibt, reicht das natürlich auch.

> Ich hab jetzt Minimalbeispiele auf meinen Server gestellt:
>
> Neu: <http://froehlich.priv.at/test.php> funktioniert nicht
> Alt: <http://froehlich.priv.at/test2.php> funktioniert

Ich krieg damit jetzt mit Firefox kein Fehlverhalten hin.

Was ich mir so an Doku heranhole sagt aber, 'return' sei deprecated, und
man möge doch bitte Event.preventDefault() benutzen.
<https://developer.mozilla.org/en-US/docs/Web/API/Event/returnValue>
<https://stackoverflow.com/questions/128923/>

Wenn's gar nicht klappen will: Ich ersetze in so einem Fall den
regulären Submit-Button durch einen Javascript-Button, der alle
Prüfungen ausführt und nur im Erfolgsfall form.submit() aufruft (also:
im DOMContentLoaded das <input type=submit> finden, löschen, und
stattdessen ein <button> o.ä. mit onclick einfügen). Quasi Whitelist
statt Blacklist.


Stefan

Stefan Froehlich

unread,
Feb 4, 2022, 3:25:24 PM2/4/22
to
On Fri, 04 Feb 2022 16:51:21 Stefan Reuther wrote:
> Am 03.02.2022 um 19:29 schrieb Stefan Froehlich:
>> On Thu, 03 Feb 2022 17:23:39 Stefan Reuther wrote:
>>> (Wenn ich das richtig sehe, muss das nonce auch noch vom Server
>>> in einem Header ausgeliefert werden? Kann der nicht gleich einen
>>> "CSP: mir egal" Header ausliefern, um alle inline-Skripte
>>> freizuschalten?)

>> Könnte er natürlich, aber damit würde sich der Kreis schließen:
>> Ich mache den Kopfstand deshalb, weil ein Security-Consultant das
>> onsubmit="" als Böse[TM] markiert hat, und sich in solchen Fällen
>> immer der größere durchsetzt - das bin nicht ich.

> Und der hat nicht angemeckert, dass man Doppel-Submit eigentlich
> auf dem Server filtern sollte? :-)

Hast Du schon einmal mit so einem Consulting zu tun gehabt? Die
arbeiten ziemlich stur eine Checkliste durch, und die ist eher
oberflächlich :-)

(Tatsächlich ist das nicht so eindimensional: Wo Transaktionen nur
1x ablaufen dürfen, fängt das der Server schon ab, aber das ist
nicht immer der Fall, und zudem kostet auch die Prüfung - manchmal
erheblich - Rechenzeit)

>> Naja, ob ich es jetzt über die Klasse oder über die Id
>> referenziere, ist dann auch schon egal

> Vorteil der Suche über den Klassennamen ist, dass man das
> Spezialverhalten automatisch überall bekommt, wo die Klasse
> benutzt wird.

Das stimmt schon, aber es bringt meine Konvention durcheinander, ids
für Skript-Zugriffe und Klassen für das Layout zu verwenden. Und am
Prinzip ändert das hier ohnehin nichts.

>> Neu: <http://froehlich.priv.at/test.php> funktioniert nicht
>> Alt: <http://froehlich.priv.at/test2.php> funktioniert
>
> Ich krieg damit jetzt mit Firefox kein Fehlverhalten hin.

Stimmt, ich sehe es im Log - sehr seltsam, denn ich habe es unter
Linux und Windows mit Chrome und Edge getestet. Aber:

> Was ich mir so an Doku heranhole sagt aber, 'return' sei
> deprecated, und man möge doch bitte Event.preventDefault()
> benutzen.
> <https://developer.mozilla.org/en-US/docs/Web/API/Event/returnValue>
> <https://stackoverflow.com/questions/128923/>

Mit, da war ja was (man merkt, Skripte führen bei mir ein echtes
Schattendasein). Ok, das gehört sowieso gleich geändert, und da sich
damit das Problem dann nicht mehr zeigt, verliert das immer noch
verwirrende Verhalten für mich ganz massiv an Relevanz. Besten Dank :-)

Servus,
Stefan

--
http://kontaktinser.at/ - die kostenlose Kontaktboerse fuer Oesterreich
Offizieller Erstbesucher(TM) von mmeike

Im Rausch der Sinne - Stefan: verlieben, welch wunderbares Vergnügen!
(Sloganizer)

Stefan Reuther

unread,
Feb 5, 2022, 4:30:51 AM2/5/22
to
Am 04.02.2022 um 21:25 schrieb Stefan Froehlich:
> On Fri, 04 Feb 2022 16:51:21 Stefan Reuther wrote:
>> Am 03.02.2022 um 19:29 schrieb Stefan Froehlich:
>>> Könnte er natürlich, aber damit würde sich der Kreis schließen:
>>> Ich mache den Kopfstand deshalb, weil ein Security-Consultant das
>>> onsubmit="" als Böse[TM] markiert hat, und sich in solchen Fällen
>>> immer der größere durchsetzt - das bin nicht ich.
>
>> Und der hat nicht angemeckert, dass man Doppel-Submit eigentlich
>> auf dem Server filtern sollte? :-)
>
> Hast Du schon einmal mit so einem Consulting zu tun gehabt? Die
> arbeiten ziemlich stur eine Checkliste durch, und die ist eher
> oberflächlich :-)

Der letzte Sicherheitsforscher[tm], mit dem ich das Vergnügen hatte,
hatte die UPnP-Service-Description meines Infotainment-Gerätes gefunden
(ein statisches XML-Dokument, das mangels Stylesheet halt ziemlich
technisch aussieht) und meinte, dass man damit den CAN-Bus hacken
könnte. Als Beleg wurde ein Screenshot eines Exploit-Frameworks
hingelegt, das sich erfolgreich auf den HTTP-Port verbunden hat.

Ergebnis: kräftig drüber gelacht und Arbeitszeit damit verschwendet, der
Chefetage zu erklären, warum das Unsinn ist.

Dabei würde ich mich echt freuen, wenn mir jemand einen Fehler
nachweist, da kann ich noch was lernen :)


Stefan

Stefan Froehlich

unread,
Feb 5, 2022, 4:56:57 AM2/5/22
to
On Sat, 05 Feb 2022 10:24:53 Stefan Reuther wrote:
> Am 04.02.2022 um 21:25 schrieb Stefan Froehlich:
>> Hast Du schon einmal mit so einem Consulting zu tun gehabt? Die
>> arbeiten ziemlich stur eine Checkliste durch, und die ist eher
>> oberflächlich :-)

> Der letzte Sicherheitsforscher[tm], mit dem ich das Vergnügen
> hatte, hatte die UPnP-Service-Description meines
> Infotainment-Gerätes gefunden (ein statisches XML-Dokument, das
> mangels Stylesheet halt ziemlich technisch aussieht) und meinte,
> dass man damit den CAN-Bus hacken könnte. Als Beleg wurde ein
> Screenshot eines Exploit-Frameworks hingelegt, das sich
> erfolgreich auf den HTTP-Port verbunden hat.

Ja, kommt mir bekannt vor. Meine Server schicken mir Emails, wenn
ihnen irgendetwas seltsam vorkommt, insbesondere wenn Anfragen
gestellt werden, die offensichtlich konstruiert, aber nicht
x-beliebig sind (also in die Logik der jeweiligen Applikation
passen).

Obiger Consultant hat also mit Grinsen im Gesucht in irgendeine
Variable "nslookup $FOO" geschrieben, das wurde erkannt und in eine
Mail verpackt, deren Inhalt wiederum ein paar Relais weiter einen
SpamAssassin dazu gebracht hat, sich dieses seltsam aussehende $FOO
kurz anzusehen. Mehr hat es nicht gebraucht: "Remote code
execution!", als Beweis dafür die Nameserver-Abfrage für $FOO.
Großes Drama überall. Meine Zeit und Nerven konnte ich niemandem
verrechnen.

> Dabei würde ich mich echt freuen, wenn mir jemand einen Fehler
> nachweist, da kann ich noch was lernen :)

In der Tat, ja. Wobei - ich *habe* durch sein Herumwuseln anderswo
tatsächlich einen Fehler gefunden, aber der war ihm nicht
aufgefallen.

Und letztendlich ist die Umstellung der uralten Event-Handler von
"return false" auf "event.preventDefault()" als Nebeneffekt eh auch
eine gute Sache, unabhängig von jeder Sicherheitsrelevanz.

Servus,
Stefan

--
http://kontaktinser.at/ - die kostenlose Kontaktboerse fuer Oesterreich
Offizieller Erstbesucher(TM) von mmeike

Für die Sekunden der Einsamkeit - mästen mit Stefan!
(Sloganizer)
0 new messages