Noch nie hat eine Religion, weder mittelbar noch unmittelbar, weder als Dogma noch als Gleichnis, eine Wahrheit enthalten.

Willkommen auf meiner Netzseite

Wer auf diesen Seiten tiefschürfende Erkenntnisse, Weltverbesserungsvorschläge oder doch wieder nur Bilder siebenachtelnackter Kopulationszielpersonen sucht, der wird leider enttäuscht werden. Meine Seite ist momentan nur dazu da, mir einen Teil meiner Verweisliste virtuell hinterherzutragen. Nein, nicht wie Mutti früher die Stullenbüchse in die Schule zur Freude der gesamten Klasse, sondern viel cooler (Das sagte man früher so.).
Sollten Sie zufällig ähnliche Männerhobbys sinnvolle Interessen haben, sich zum Beispiel für Geschichte, Rechentechnik, Photographie, lange Sätze oder alte Kraftfahrzeuge interessieren, und hier den ein oder anderen Verweis finden, der dazu führt, daß Sie den Abend vor dem Rechner und nicht mit Ihrer besseren Hälfte verbringen, so tut es mir Leid. Natürlich war das alles überhaupt nicht so gewollt.

JavaScript-Zugangsschutz für Spaßvögel

In den Weiten des Netzes stößt man immer wieder auf kreative Seitenbetreiber, die ihre Netzseiten mit Hilfe von JS-Skripten gegen fremden Zugriff schützen wollen. Die meisten Lösungen fallen unter "security by obscurity", haben also ein Sicherheitsniveau knapp über dem direkten Anzeigen der "versteckten" Inhalte, aber weit unter dem eines Kaugummiautomaten.

Im einfachsten Fall steht das Paßwort oder die gesuchte Seite direkt im Quelltext oder es hilft ein alert(); an der richtigen Stelle, um Sicherheitvorgaukelfunktionen zu umgehen. Nur in wenigen Fällen muß man wirklich nachdenken und Algorithmen nachvollziehen, um an die gewünschten Daten zu gelangen. Schade eigentlich.

Am häufigsten wird aus dem Paßwort der Name der "versteckten" Seite generiert. Wobei "generiert" oftmals stark übertrieben ist und das Paßwort einfach als Seitenadresse wiederverwendet wird. Es muß wohl am proprietären JScript-Encode, zu dem es natürlich ein passendes Decode gibt, liegen, daß es zu den sichersten Varianten gehört:

Description: NoPass is a password security system that can be used to protect web pages and files. As it is impossible to obtain the password from the source code, NoPass is very secure for a JavaScript of its kind. Possibly the most secure JavaScript password protection available. [...]

Mit ein paar unnützen Sicherheitvorgaukel- bzw. Quelltextfüllfunktionen kann man solch einen Quatsch auch für echtes(!) Geld (ver-)kaufen.

Vor kurzem1 bin ich allerdings auf ein besonders niedliches Exemplar (Site Protector 5.x)2 gestoßen3, das auf der Autorenseite mit:

How well are the pages protected?

They aren't completely protected because it's only client-side javaScript-Protection. But it's still very well protected in the sense that everything is encrypted and the password isn't included directly. Many people have tried to break this protection - all have failed :-)

beworben wird. Der Smiley deutet schon in die richtige Richtung.

Netterweise gibt es gleich eine Demoseite, um sich den Quelltext anzusehen:

<SCRIPT LANGUAGE="JavaScript"><!--
var sp_trys = 3;var sp_alpha="ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789-:/._abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";var sp_a1=new Array(); var sp_a2=new Array();
sp_a1[0]=11; sp_a2[0]="_h.h_gDxnypwfwuB.mfvpB.ysxundCfm_quvm";
function sp() {var pass="";var revisit=false;if (! revisit) {pass = prompt("Please enter your password.","");}if(pass==null || pass=="") {location.href='../../Components/demos/access.html';}else {if (revisit) {h1=pass.substring(0,pass.indexOf("|"));h2=pass.substring(pass.indexOf("|")+1);} else {h1=sp_makehash(pass,3); h2=sp_makehash(pass,10)+" ";}for (var pos=0;pos<sp_a1.length;pos++) if (sp_a1[pos]==h1) break;if (pos==sp_a1.length) {sp_trys--;if (sp_trys > 0) {if (confirm("\nThe password is invalid. Try again?")) sp();else location.href='../../Components/demos/access.html';} else location.href='../../Components/demos/access.html';return;}var page=""; var hp=0;for (var i=0;i<sp_a2[pos].length;i++) {letter=sp_a2[pos].substring(i,i+1);a=sp_alpha.indexOf(letter,0);if (a>=0) {a-=(h2.substring(hp,hp+1)*1);hp++; if (hp==h2.length-1) hp=0;if (a<0) a+=68;page+=sp_alpha.substring(a,a+1);} else { page+=letter; }}location.href=page;}}
function sp_makehash(pw,mult) {hash=0;for (i=0;i<pw.length;i++) {letter=pw.substring(i,i+1);c=sp_alpha.indexOf(letter,0)+1;hash=(hash*mult+c)%27;}return(hash);}
//SiteProtector 5.x by Ingo Fischer (http://www.apollon.de) --></SCRIPT>

Nach dem Formatieren mit vim:

<script type="text/javascript">
    var sp_trys = 3;
    var sp_alpha="ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789-:/._abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    var sp_a1=new Array();
    var sp_a2=new Array();

    sp_a1[0]=11;
    sp_a2[0]="_h.h_gDxnypwfwuB.mfvpB.ysxundCfm_quvm";

    function sp() {
        var pass="";
        var revisit=false;

        if (! revisit) {
            pass = prompt("Please enter your password.","");
        }

        if(pass==null || pass=="") {
            location.href='../../Components/demos/access.html';
        } else {
            if (revisit) {
                h1=pass.substring(0,pass.indexOf("|"));
                h2=pass.substring(pass.indexOf("|")+1);
            } else {
                h1=sp_makehash(pass,3);
                h2=sp_makehash(pass,10)+" ";
            }

            for (var pos=0;pos<sp_a1.length;pos++)
                if (sp_a1[pos]==h1)
                    break;

            if (pos==sp_a1.length) {
                sp_trys--;

                if (sp_trys > 0) {
                    if (confirm("\nThe password is invalid. Try again?"))
                        sp();
                    else location.href='../../Components/demos/access.html';
                } else
                    location.href='../../Components/demos/access.html';return;
            }

            var page="";
            var hp=0;

            for (var i=0;i<sp_a2[pos].length;i++) {
                letter=sp_a2[pos].substring(i,i+1);
                a=sp_alpha.indexOf(letter,0);

                if (a>=0) {
                    a-=(h2.substring(hp,hp+1)*1);
                    hp++;

                    if (hp==h2.length-1)
                        hp=0;
                    if (a<0)
                        a+=68;

                    page+=sp_alpha.substring(a,a+1);
                } else {
                    page+=letter;
                }
            }

            location.href=page;
        }
    }

    function sp_makehash(pw,mult) {
        hash=0;

        for (i=0;i<pw.length;i++) {
            letter=pw.substring(i,i+1);
            c=sp_alpha.indexOf(letter,0)+1;
            hash=(hash*mult+c)%27;
        }

        return(hash);
    }

//SiteProtector 5.x by Ingo Fischer (http://www.apollon.de) -->
</script>

Wenn man sich die Variableninitialisierung in der sp()-Funktion anschaut und dann alles wegwirft, was man in der Funktion nicht braucht, erhält man:

    function sp() {
        h1=sp_makehash(pass,3);
        h2=sp_makehash(pass,10)+" ";

        for (var pos=0;pos<sp_a1.length;pos++)
            if (sp_a1[pos]==h1)
                break;

        var page="";
        var hp=0;

        for (var i=0;i<sp_a2[pos].length;i++) {
            letter=sp_a2[pos].substring(i,i+1);
            a=sp_alpha.indexOf(letter,0);

            if (a>=0) {
                a-=(h2.substring(hp,hp+1)*1);
                hp++;

                if (hp==h2.length-1)
                    hp=0;
                if (a<0)
                    a+=68;

                page+=sp_alpha.substring(a,a+1);
            } else {
                page+=letter;
            }
        }

            location.href=page;
    }

Die for-Schleife wird wohl benutzt, um mehrere Seiten mit verschiedenen Kennwörtern zu versehen. Die Hash-Werte(!) der Paßwörter dienen über pos als Index für die "verschlüsselten" Seitennamen. In diesem Fall gibt es allerdings nur eine Seite, also können wir pos mit 0 initialisieren und h1 links liegen lassen.

Wenigstens hat der Autor nicht die Klartexte verwendet und die Hash-Berechnung über den zweiten Parameter verändert.

Wir schreiben um:

    function sp() {
        h2=sp_makehash(pass,10)+" ";
        pos=0;

        var page="";
        var hp=0;

        for (var i=0;i<sp_a2[pos].length;i++) {
            letter=sp_a2[pos].substring(i,i+1);
            a=sp_alpha.indexOf(letter,0);

            if (a>=0) {
                a-=(h2.substring(hp,hp+1)*1);
                hp++;

                if (hp==h2.length-1)
                    hp=0;
                if (a<0)
                    a+=68;

                page+=sp_alpha.substring(a,a+1);
            } else {
                page+=letter;
            }
        }

            location.href=page;
    }

Kennwortverkrüppeln

An dieser Stelle wird es im Normalfall etwas haarig, allerdings hilft uns der Autor weiter. Will er etwa selbst Zugang zu den Seiten, wird er von Geheimdiensten bezahlt oder implementiert er gar Abhörvorgaben der Regierung? Die Hash-Funktion erweist sich als vollkommen ungenügend. Das Modulo am Ende sorgt dafür, daß nur 27 verschiedene Werte zurückgegeben werden. Wer also "Heinz" und "Karin" als Kennwörter wählt, kann wegen des obigen Hash-Index keine zwei verschiedenen Seiten pseudoschützen. Egal, wie gut man das Paßwort wählt, es wird immer auf maximal zwei Stellen gestutzt.

    function sp_makehash(pw,mult) {
        hash=0;

        for (i=0;i<pw.length;i++) {
            letter=pw.substring(i,i+1);
            c=sp_alpha.indexOf(letter,0)+1;
            hash=(hash*mult+c)%27;
        }

        return(hash);
    }

Lassen wir uns doch einfach alle möglichen Werte zurückgeben:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=iso-8859-1" />

<script type="text/javascript">
    var sp_alpha="ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789-:/._abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    var sp_a1=new Array();
    var sp_a2=new Array();

    sp_a1[0]=11;
    sp_a2[0]="_h.h_gDxnypwfwuB.mfvpB.ysxundCfm_quvm";

    var siteurl="http://www.apollon.de/Components/demos/";

    function sp() {
        var h2="";
        var pos=0;

        for (var th2=0;th2<27;th2++) {
            var page="";
            var hp=0;

            h2 = th2 + " ";

            for (var i=0;i<sp_a2[pos].length;i++) {
                letter=sp_a2[pos].substring(i,i+1);
                a=sp_alpha.indexOf(letter,0);

                if (a>=0) {
                    a-=(h2.substring(hp,hp+1)*1);
                    hp++;

                    if (hp==h2.length-1)
                        hp=0;
                    if (a<0)
                        a+=68;

                    page+=sp_alpha.substring(a,a+1);
                } else {
                    page+=letter;
                }
            }

            document.write(th2+'. <a href="'+siteurl+page+'">'+siteurl+page+'</a><br />');
        }
    }

sp();

//SiteProtector 5.x by Ingo Fischer (http://www.apollon.de)
</script>

</head><body></body></html>

Das liefert uns:

0. http://www.apollon.de/Components/demos/_h.h_gDxnypwfwuB.mfvpB.ysxundCfm_quvm
1. http://www.apollon.de/Components/demos/.g/g.fCwmxovevtA/leuoA/xrwtmcBel.ptul
2. http://www.apollon.de/Components/demos//f:f/eBvlwnudusz:kdtnz:wqvslbAdk/ostk
3. http://www.apollon.de/Components/demos/:e-e:dAukvmtctry-jcsmy-vpurkazcj:nrsj
4. http://www.apollon.de/Components/demos/-d9d-cztjulsbsqx9ibrlx9uotqj_ybi-mqri
5. http://www.apollon.de/Components/demos/9c8c9bysitkrarpw8haqkw8tnspi.xah9lpqh
6. http://www.apollon.de/Components/demos/8b7b8axrhsjq_qov7g_pjv7smroh/w_g8kopg
7. http://www.apollon.de/Components/demos/7a6a7_wqgrip.pnu6f.oiu6rlqng:v.f7jnof
8. http://www.apollon.de/Components/demos/6_5_6.vpfqho/omt5e/nht5qkpmf-u/e6imne
9. http://www.apollon.de/Components/demos/5.4.5/uoepgn:nls4d:mgs4pjole9t:d5hlmd
10. http://www.apollon.de/Components/demos/.h/h.gCxmyowewtB/mevoB/yrxtncCem.qtvl
11. http://www.apollon.de/Components/demos/.g/g.fCwmxovevtA/leuoA/xrwtmcBel.ptul
12. http://www.apollon.de/Components/demos/.f/f.eCvmwoueutz/ketoz/wrvtlcAek.ottl
13. http://www.apollon.de/Components/demos/.e/e.dCumvotetty/jesoy/vrutkczej.ntsl
14. http://www.apollon.de/Components/demos/.d/d.cCtmuosestx/ierox/urttjcyei.mtrl
15. http://www.apollon.de/Components/demos/.c/c.bCsmtorertw/heqow/trsticxeh.ltql
16. http://www.apollon.de/Components/demos/.b/b.aCrmsoqeqtv/gepov/srrthcweg.ktpl
17. http://www.apollon.de/Components/demos/.a/a._Cqmropeptu/feoou/rrqtgcvef.jtol
18. http://www.apollon.de/Components/demos/._/_..Cpmqooeott/eenot/qrptfcuee.itnl
19. http://www.apollon.de/Components/demos/../../Components/demos/protected.html
20. http://www.apollon.de/Components/demos//h:h/gBxlynwdwsB:mdvnB:yqxsnbCdm/qsvk
21. http://www.apollon.de/Components/demos//g:g/fBwlxnvdvsA:ldunA:xqwsmbBdl/psuk
22. http://www.apollon.de/Components/demos//f:f/eBvlwnudusz:kdtnz:wqvslbAdk/ostk
23. http://www.apollon.de/Components/demos//e:e/dBulvntdtsy:jdsny:vquskbzdj/nssk
24. http://www.apollon.de/Components/demos//d:d/cBtlunsdssx:idrnx:uqtsjbydi/msrk
25. http://www.apollon.de/Components/demos//c:c/bBsltnrdrsw:hdqnw:tqssibxdh/lsqk
26. http://www.apollon.de/Components/demos//b:b/aBrlsnqdqsv:gdpnv:sqrshbwdg/kspk

Eine der anderen Varianten wäre besser gewesen...

In allen Fällen, die ich gesehen habe, war der url lesbar, fing mit "../../" an und endete mit ".htm[l]" - den NOF-Webdesignern sei Dank. Allerdings können die Bezeichner im Skript variieren.

Paßwort gefällig?

Die Zeilennummer in unserer Ausgabe gibt den zweiten Hash-Wert h2 an. Damit haben wir alles, was unser Paßwort ausmacht - zwei maximal zweistellige Hash-Werte (bzw. einer, wenn man nur die Seite wissen will).

Einfach eine beliebige lange Liste nehmen, die Hash-Paare berechnen, sortieren:

h2,h1 (Kennwort)
--+--+-----------------
 0, 0 (Wunschtroll)
[...]
19,11 (Bananenhure)
19,11 (Ikonoklast)
19,11 (Luegenschwein)
19,11 (Promillepapst)
19,11 (Schnepfe)
19,11 (Schwabbelhure)
[...]
26,26 (Zwiederwurzen)

und ein passendes Paar herausnehmen. Ein (11,19)-Paar wäre "Schnepfe", also brauchen wir auch die Lösung "apollon" von der Demoseite nicht mehr. Obwohl - haben wir die jemals gebraucht? ;)

Anmerkung

Falls Ihr doch noch Lust habt und Euch trotz Lösung den Algorithmus genauer ansehen wollt, achtet mal darauf, wie sehr sich die Verschlüsselungsqualität in Abhängigkeit vom Paßwort ändert oder wie ein "?" kodiert wird. (Wenn man hier überhaupt von Verschlüsselung sprechen kann.)

(0,0)-Kennwort "Wunschtroll":

site : ../../Components/demos/protected.html
crypt: ../../Components/demos/protected.html

  1. Man möge mir verzeihen, daß ich mit den html-uglifiern wie Fusion nicht vertraut bin. Ich mache das per Hand. ;)
  2. Dieses "Programm" wurde vor Jahren im Zusammenhang mit Netobjects Fusion verwendet und wird heute nicht mehr weiterentwickelt. Einige private und Vereinsseiten nutzen heute noch diesen "Schutz", was an der Werbung auf diversen Supportseiten liegen kann. Einen Fehlerbericht gab es anscheinend nie.
  3. Jeder hat so seine Freuden - andere schreiben Zahlen in 9x9-Gitter.
Frank Busse Dresden 2005