Wie deaktiviert Facebook die integrierten Entwicklertools des Browsers?


1685

Anscheinend werden die Entwicklertools aufgrund der jüngsten Betrugsversuche von Leuten zum Posten von Spam ausgenutzt und sogar zum "Hacken" von Konten verwendet. Facebook hat die Entwicklertools blockiert und ich kann nicht einmal die Konsole verwenden.

Geben Sie hier die Bildbeschreibung ein

Wie haben sie das gemacht? Ein Beitrag zum Stapelüberlauf behauptete, dass dies nicht möglich sei , aber Facebook hat bewiesen, dass sie falsch sind.

Gehen Sie einfach zu Facebook und öffnen Sie die Entwicklertools, geben Sie ein Zeichen in die Konsole ein, und diese Warnung wird angezeigt. Egal was Sie eingeben, es wird nicht ausgeführt.

Wie ist das möglich?

Sie haben sogar die automatische Vervollständigung in der Konsole blockiert:

Geben Sie hier die Bildbeschreibung ein


21
Nur zum Spaß: console.log = function () {}
tnt-rox

Haben Sie eine Lösung gefunden, wie sie die automatische Vervollständigung in der Konsole blockiert haben
Akshay Hegde

1
@AkshayHegde Es war ein Nebeneffekt, der durch das Blockieren der Codeausführung von den devtools verursacht wurde.
Derek 28 會 功夫

@Derek 朕 會 功夫 können Sie bitte Code teilen
Akshay Hegde

Nur zu Ihrer Information, es ist nicht mehr in Chrom blockiert.
John Lord

Antworten:


2437

Ich bin Sicherheitsingenieur bei Facebook und das ist meine Schuld. Wir testen dies für einige Benutzer, um festzustellen, ob es einige Angriffe verlangsamen kann, bei denen Benutzer dazu verleitet werden, (böswilligen) JavaScript-Code in die Browserkonsole einzufügen.

Um ganz klar zu sein: Der Versuch, Hacker clientseitig zu blockieren, ist im Allgemeinen eine schlechte Idee . Dies dient dem Schutz vor einem bestimmten Social-Engineering-Angriff .

Wenn Sie in der Testgruppe gelandet sind und sich darüber ärgern, tut mir leid. Ich habe versucht, die alte Opt-out-Seite (jetzt Hilfeseite ) so einfach wie möglich zu gestalten, während ich immer noch beängstigend genug war, um zumindest einige der Opfer aufzuhalten .

Der eigentliche Code ist dem Link von @ joeldixon66 ziemlich ähnlich . Unsere ist ohne guten Grund etwas komplizierter.

Chrome schließt den gesamten Konsolencode ein

with ((console && console._commandLineAPI) || {}) {
  <code goes here>
}

... also definiert die Seite neu console._commandLineAPIzu werfen:

Object.defineProperty(console, '_commandLineAPI',
   { get : function() { throw 'Nooo!' } })

Das ist nicht genug (probieren Sie es aus!) , Aber das ist der Haupttrick.


Epilog: Das Chrome-Team entschied, dass das Besiegen der Konsole von benutzerseitigem JS ein Fehler war, und behebte das Problem , wodurch diese Technik ungültig wurde. Anschließend wurde ein zusätzlicher Schutz hinzugefügt, um Benutzer vor Self-XSS zu schützen .


10
Chrome hat ein Update gemacht, aber dieser Typ hat wieder eine Korrektur vorgenommen: kspace.in/blog/2014/06/21/…
Roger Gajraj

3
@Alf, auf Ihrer Opt-Out-Seite wird jetzt die Hilfeseite angezeigt, ohne dass der Schutz deaktiviert werden kann.
arm.localhost

168
Bitte brechen Sie die Entwicklertools nicht wegen der Dummheit einiger Benutzer. "Lösungen" wie diese lassen mich vor einer Million Sonnen brennen.
Jonathan Dunlap

85
Ich denke, Google muss eine "sichere" Version von Chrome, keine DevTools, veröffentlichen und jeden, der automatische Updates erhält, dazu zwingen, nur einmal zu dieser Version zu wechseln. Jeder Entwickler, der den Unterschied tatsächlich bemerkt und die DevTools benötigt, sollte die "beängstigende" Version herunterladen. Beschriften Sie sie direkt auf der Download-Seite als "Scary" und "Safe" und halten Sie Darwinisten davon ab, sich selbst Schaden zuzufügen, indem Sie ausdrücklich angeben: "Sie sind wahrscheinlich hier, weil Sie aufgrund eines Social-Engineering-Angriffs aufgefordert wurden, die Scary-Version herunterzuladen. Bitte nicht." mach das." Gott segne euch FB-Entwickler dafür, dass ihr so ​​kreativ seid!
MonkeyZeus

11
@ n00b Diese Warnmeldung ist nur eine console.log.
Gcampbell

91

Ich habe das Console Buster-Skript von Facebook mithilfe der Chrome-Entwicklertools gefunden. Hier ist das Skript mit geringfügigen Änderungen zur besseren Lesbarkeit. Ich habe die Teile entfernt, die ich nicht verstehen konnte:

Object.defineProperty(window, "console", {
    value: console,
    writable: false,
    configurable: false
});

var i = 0;
function showWarningAndThrow() {
    if (!i) {
        setTimeout(function () {
            console.log("%cWarning message", "font: 2em sans-serif; color: yellow; background-color: red;");
        }, 1);
        i = 1;
    }
    throw "Console is disabled";
}

var l, n = {
        set: function (o) {
            l = o;
        },
        get: function () {
            showWarningAndThrow();
            return l;
        }
    };
Object.defineProperty(console, "_commandLineAPI", n);
Object.defineProperty(console, "__commandLineAPI", n);

Damit schlägt die automatische Vervollständigung der Konsole stillschweigend fehl, während in die Konsole eingegebene Anweisungen nicht ausgeführt werden können (die Ausnahme wird protokolliert).

Verweise:


48

Ich konnte es auf keiner Seite dazu bringen, das auszulösen. Eine robustere Version davon würde es tun:

window.console.log = function(){
    console.error('The developer console is temp...');
    window.console.log = function() {
        return false;
    }
}

console.log('test');

So gestalten Sie die Ausgabe: Farben in der JavaScript-Konsole

Edit Thinking @ joeldixon66 hat die richtige Idee: Deaktivieren Sie die JavaScript-Ausführung über die Konsole «::: KSpace :::


cool one aber überschreibe dann immer noch das gleiche window.console.log = function(){//empty}und benutze console.log
super cool

32

Neben der Neudefinition console._commandLineAPIgibt es einige andere Möglichkeiten, in InjectedScriptHost in WebKit-Browsern einzudringen, um die Auswertung von in die Entwicklerkonsole eingegebenen Ausdrücken zu verhindern oder zu ändern.

Bearbeiten:

Chrome hat dies in einer früheren Version behoben. - das muss vor Februar 2015 gewesen sein, als ich das Wesentliche zu dieser Zeit erstellt habe

Also hier ist eine andere Möglichkeit. Dieses Mal schließen wir uns ein Level höher direkt an InjectedScriptund nicht InjectedScriptHostim Gegensatz zur vorherigen Version.

Das ist ein bisschen nett, da Sie Affen-Patches direkt ausführen können, InjectedScript._evaluateAndWrapanstatt sich darauf verlassen zu müssen, InjectedScriptHost.evaluateda Sie dadurch eine genauere Kontrolle darüber haben, was passieren soll.

Eine andere ziemlich interessante Sache ist, dass wir das interne Ergebnis abfangen können, wenn ein Ausdruck ausgewertet wird, und dieses anstelle des normalen Verhaltens an den Benutzer zurückgeben können.

Hier ist der Code, der genau das tut und das interne Ergebnis zurückgibt, wenn ein Benutzer etwas in der Konsole auswertet.

var is;
Object.defineProperty(Object.prototype,"_lastResult",{
   get:function(){
       return this._lR;
   },
   set:function(v){
       if (typeof this._commandLineAPIImpl=="object") is=this;
       this._lR=v;
   }
});
setTimeout(function(){
   var ev=is._evaluateAndWrap;
   is._evaluateAndWrap=function(){
       var res=ev.apply(is,arguments);
       console.log();
       if (arguments[2]==="completion") {
           //This is the path you end up when a user types in the console and autocompletion get's evaluated

           //Chrome expects a wrapped result to be returned from evaluateAndWrap.
           //You can use `ev` to generate an object yourself.
           //In case of the autocompletion chrome exptects an wrapped object with the properties that can be autocompleted. e.g.;
           //{iGetAutoCompleted: true}
           //You would then go and return that object wrapped, like
           //return ev.call (is, '', '({test:true})', 'completion', true, false, true);
           //Would make `test` pop up for every autocompletion.
           //Note that syntax as well as every Object.prototype property get's added to that list later,
           //so you won't be able to exclude things like `while` from the autocompletion list,
           //unless you wou'd find a way to rewrite the getCompletions function.
           //
           return res; //Return the autocompletion result. If you want to break that, return nothing or an empty object
       } else {
           //This is the path where you end up when a user actually presses enter to evaluate an expression.
           //In order to return anything as normal evaluation output, you have to return a wrapped object.

           //In this case, we want to return the generated remote object. 
           //Since this is already a wrapped object it would be converted if we directly return it. Hence,
           //`return result` would actually replicate the very normal behaviour as the result is converted.
           //to output what's actually in the remote object, we have to stringify it and `evaluateAndWrap` that object again.`
           //This is quite interesting;
           return ev.call (is, null, '(' + JSON.stringify (res) + ')', "console", true, false, true)
       }
   };
},0);

Es ist ein bisschen ausführlich, aber ich dachte, ich habe ein paar Kommentare hinzugefügt

Wenn ein Benutzer beispielsweise auswertet [1,2,3,4], erwarten Sie normalerweise die folgende Ausgabe:

Geben Sie hier die Bildbeschreibung ein

Nach dem Monkeypatching InjectedScript._evaluateAndWrap, das denselben Ausdruck auswertet, wird die folgende Ausgabe ausgegeben:

Geben Sie hier die Bildbeschreibung ein

Wie Sie sehen, ist der kleine linke Pfeil, der die Ausgabe anzeigt, immer noch vorhanden, aber dieses Mal erhalten wir ein Objekt. Wenn das Ergebnis des Ausdrucks ist, wird das Array [1,2,3,4]als Objekt mit allen beschriebenen Eigenschaften dargestellt.

Ich empfehle, diesen und jenen Ausdruck zu bewerten, einschließlich derer, die Fehler erzeugen. Es ist ziemlich interessant.

Schauen Sie sich außerdem das is - InjectedScriptHost- Objekt an. Es bietet einige Methoden zum Spielen und um einen Einblick in die Interna des Inspektors zu erhalten.

Natürlich können Sie all diese Informationen abfangen und trotzdem das ursprüngliche Ergebnis an den Benutzer zurückgeben.

Ersetzen Sie einfach die return-Anweisung im else-Pfad durch ein console.log (res)folgendes a return res. Dann würden Sie am Ende mit dem folgenden enden.

Geben Sie hier die Bildbeschreibung ein

Ende der Bearbeitung


Dies ist die vorherige Version, die von Google behoben wurde. Daher kein möglicher Weg mehr.

Eines davon hakt sich ein Function.prototype.call

Chrome wertet den eingegebenen Ausdruck aus, indem es callseine Bewertungsfunktion mit InjectedScriptHostas angibtthisArg

var result = evalFunction.call(object, expression);

Vor diesem Hintergrund können Sie für das hören thisArgvon callWesen evaluateund einen Verweis auf das erste Argument bekommen ( InjectedScriptHost)

if (window.URL) {
    var ish, _call = Function.prototype.call;
    Function.prototype.call = function () { //Could be wrapped in a setter for _commandLineAPI, to redefine only when the user started typing.
        if (arguments.length > 0 && this.name === "evaluate" && arguments [0].constructor.name === "InjectedScriptHost") { //If thisArg is the evaluate function and the arg0 is the ISH
            ish = arguments[0];
            ish.evaluate = function (e) { //Redefine the evaluation behaviour
                throw new Error ('Rejected evaluation of: \n\'' + e.split ('\n').slice(1,-1).join ("\n") + '\'');
            };
            Function.prototype.call = _call; //Reset the Function.prototype.call
            return _call.apply(this, arguments);  
        }
    };
}

Sie könnten zB einen Fehler auslösen, dass die Auswertung abgelehnt wurde.

Geben Sie hier die Bildbeschreibung ein

Hier ist ein Beispiel, in dem der eingegebene Ausdruck an einen CoffeeScript-Compiler übergeben wird, bevor er an die evaluateFunktion übergeben wird.


25

Netflix implementiert diese Funktion ebenfalls

(function() {
    try {
        var $_console$$ = console;
        Object.defineProperty(window, "console", {
            get: function() {
                if ($_console$$._commandLineAPI)
                    throw "Sorry, for security reasons, the script console is deactivated on netflix.com";
                return $_console$$
            },
            set: function($val$$) {
                $_console$$ = $val$$
            }
        })
    } catch ($ignore$$) {
    }
})();

Sie überschreiben nur, um console._commandLineAPISicherheitsfehler auszulösen.


24

Dies ist tatsächlich möglich, da Facebook dies konnte. Nun, nicht die eigentlichen Webentwickler-Tools, sondern die Ausführung von Javascript in der Konsole.

Siehe dies: Wie deaktiviert Facebook die integrierten Entwicklertools des Browsers?

Dies wird jedoch nicht viel bewirken, da es andere Möglichkeiten gibt, diese Art der clientseitigen Sicherheit zu umgehen.

Wenn Sie sagen, dass es clientseitig ist, geschieht dies außerhalb der Kontrolle des Servers, sodass Sie nicht viel dagegen tun können. Wenn Sie sich fragen, warum Facebook dies immer noch tut, dient dies nicht der Sicherheit, sondern dem Schutz normaler Benutzer, die kein Javascript kennen, vor dem Ausführen von Code (den sie nicht lesen können) in die Konsole. Dies ist häufig bei Websites der Fall, die einen Auto-Liker-Service oder andere Facebook-Funktions-Bots versprechen, nachdem Sie das getan haben, was sie von Ihnen verlangen. In den meisten Fällen erhalten Sie einen Ausschnitt aus Javascript, der in der Konsole ausgeführt werden kann.

Wenn Sie nicht so viele Nutzer wie Facebook haben, müssen Sie meiner Meinung nach nicht das tun, was Facebook tut.

Selbst wenn Sie Javascript in der Konsole deaktivieren, ist das Ausführen von Javascript über die Adressleiste weiterhin möglich.

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

und wenn der Browser Javascript in der Adressleiste deaktiviert (wenn Sie Code in die Adressleiste in Google Chrome einfügen, wird der Ausdruck "Javascript:" gelöscht), ist das Einfügen von Javascript in einen der Links über das Inspect-Element weiterhin möglich.

Überprüfen Sie den Anker:

Geben Sie hier die Bildbeschreibung ein

Code in href einfügen:

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Unterm Strich ist die serverseitige Validierung und die Sicherheit sollte zuerst erfolgen, danach die clientseitige.


11

Chrome hat sich sehr verändert, seit Facebook die Konsole deaktivieren konnte ...

Ab März 2017 funktioniert das nicht mehr.

Am besten deaktivieren Sie einige der Konsolenfunktionen. Beispiel:

if(!window.console) window.console = {};
var methods = ["log", "debug", "warn", "info", "dir", "dirxml", "trace", "profile"];
for(var i=0;i<methods.length;i++){
    console[methods[i]] = function(){};
}

9

Mein einfacher Weg, aber es kann für weitere Variationen zu diesem Thema helfen. Listen Sie alle Methoden auf und ändern Sie sie in nutzlos.

  Object.getOwnPropertyNames(console).filter(function(property) {
     return typeof console[property] == 'function';
  }).forEach(function (verb) {
     console[verb] =function(){return 'Sorry, for security reasons...';};
  });

5

Intern fügt devtools ein IIFE mit dem Namen getCompletionsin die Seite ein, das aufgerufen wird, wenn eine Taste in der Devtools-Konsole gedrückt wird.

Bei Betrachtung der Quelle dieser Funktion werden einige globale Funktionen verwendet, die überschrieben werden können.

Mit dem ErrorKonstruktor ist es möglich, den Aufrufstapel getCompletionsabzurufen , der beim Aufruf durch Devtools enthalten ist.


Beispiel:

const disableDevtools = callback => {
  const original = Object.getPrototypeOf;

  Object.getPrototypeOf = (...args) => {
    if (Error().stack.includes("getCompletions")) callback();
    return original(...args);
  };
};

disableDevtools(() => {
  console.error("devtools has been disabled");

  while (1);
});


Das ist ziemlich ordentlich, aber es stürzt auch die Seite ab.
Derek 29 會 功夫

@Derek 朕 會 功夫 Nur Weg (ich habe gefunden), um weitere Benutzereingaben zu unterdrücken
samdd

Ich frage mich, ob Sie einen Fehler auslösen können, anstatt eine Endlosschleife zu verwenden. Bearbeiten: Getestet, funktioniert nicht.
Derek 29 會 功夫

@Derek 朕 會 功夫 es ist in einem Try-Catch-Block. Sie könnten wahrscheinlich die Funktionen über dem Block überschreiben, aber es würde nur die automatische Vervollständigung (keine Auswertung) verhindern
samdd

2

eine einfache Lösung!

setInterval(()=>console.clear(),1500);

1
Wie deaktiviert dies die console.log()?
Red

1
console.log()spielt keine
Rolle

Das ist eine schlechte Idee. Hacker können von ihrem Terminal aus verfolgen und alle Protokolle anzeigen.
GFxJamal

4
und wenn Sie Preserve Logs markieren, tut console.clear () nichts: P
Zibri

0

Ich würde den Weg gehen von:

Object.defineProperty(window, 'console', {
  get: function() {

  },
  set: function() {

  }
});

-2

Dies ist keine Sicherheitsmaßnahme dafür, dass schwacher Code unbeaufsichtigt bleibt. Holen Sie sich immer eine dauerhafte Lösung für schwachen Code und sichern Sie Ihre Websites ordnungsgemäß, bevor Sie diese Strategie implementieren

Meines Wissens nach wäre das mit Abstand beste Tool das Hinzufügen mehrerer Javascript-Dateien, die einfach die Integrität der Seite durch Aktualisieren oder Ersetzen von Inhalten wieder auf den Normalwert zurücksetzen. Das Deaktivieren dieses Entwicklertools wäre nicht die beste Idee, da das Umgehen immer in Frage kommt, da der Code Teil des Browsers und kein Server-Rendering ist und daher möglicherweise geknackt wird.

Wenn Sie js file onenach <element>Änderungen an wichtigen Elementen suchen js file twound js file threeüberprüfen, ob diese Datei pro Zeitraum vorhanden ist, wird die vollständige Integrität der Seite innerhalb des Zeitraums wiederhergestellt.

Nehmen wir ein Beispiel der 4 Dateien und zeigen Ihnen, was ich meine.

index.html

   <!DOCTYPE html>
   <html>
   <head id="mainhead">
   <script src="ks.js" id="ksjs"></script>
   <script src="mainfile.js" id="mainjs"></script>
   <link rel="stylesheet" href="style.css" id="style">
   <meta id="meta1" name="description" content="Proper mitigation against script kiddies via Javascript" >
   </head>
   <body>
   <h1 id="heading" name="dontdel" value="2">Delete this from console and it will refresh. If you change the name attribute in this it will also refresh. This is mitigating an attack on attribute change via console to exploit vulnerabilities. You can even try and change the value attribute from 2 to anything you like. If This script says it is 2 it should be 2 or it will refresh. </h1>
   <h3>Deleting this wont refresh the page due to it having no integrity check on it</h3>

   <p>You can also add this type of error checking on meta tags and add one script out of the head tag to check for changes in the head tag. You can add many js files to ensure an attacker cannot delete all in the second it takes to refresh. Be creative and make this your own as your website needs it. 
   </p>

   <p>This is not the end of it since we can still enter any tag to load anything from everywhere (Dependent on headers etc) but we want to prevent the important ones like an override in meta tags that load headers. The console is designed to edit html but that could add potential html that is dangerous. You should not be able to enter any meta tags into this document unless it is as specified by the ks.js file as permissable. <br>This is not only possible with meta tags but you can do this for important tags like input and script. This is not a replacement for headers!!! Add your headers aswell and protect them with this method.</p>
   </body>
   <script src="ps.js" id="psjs"></script>
   </html>

mainfile.js

   setInterval(function() {
   // check for existence of other scripts. This part will go in all other files to check for this file aswell. 
   var ksExists = document.getElementById("ksjs"); 
   if(ksExists) {
   }else{ location.reload();};

   var psExists = document.getElementById("psjs");
   if(psExists) {
   }else{ location.reload();};

   var styleExists = document.getElementById("style");
   if(styleExists) {
   }else{ location.reload();};


   }, 1 * 1000); // 1 * 1000 milsec

ps.js

   /*This script checks if mainjs exists as an element. If main js is not existent as an id in the html file reload!You can add this to all js files to ensure that your page integrity is perfect every second. If the page integrity is bad it reloads the page automatically and the process is restarted. This will blind an attacker as he has one second to disable every javascript file in your system which is impossible.

   */

   setInterval(function() {
   // check for existence of other scripts. This part will go in all other files to check for this file aswell. 
   var mainExists = document.getElementById("mainjs"); 
   if(mainExists) {
   }else{ location.reload();};

   //check that heading with id exists and name tag is dontdel.
   var headingExists = document.getElementById("heading"); 
   if(headingExists) {
   }else{ location.reload();};
   var integrityHeading = headingExists.getAttribute('name');
   if(integrityHeading == 'dontdel') {
   }else{ location.reload();};
   var integrity2Heading = headingExists.getAttribute('value');
   if(integrity2Heading == '2') {
   }else{ location.reload();};
   //check that all meta tags stay there
   var meta1Exists = document.getElementById("meta1"); 
   if(meta1Exists) {
   }else{ location.reload();};

   var headExists = document.getElementById("mainhead"); 
   if(headExists) {
   }else{ location.reload();};

   }, 1 * 1000); // 1 * 1000 milsec

ks.js

   /*This script checks if mainjs exists as an element. If main js is not existent as an id in the html file reload! You can add this to all js files to ensure that your page integrity is perfect every second. If the page integrity is bad it reloads the page automatically and the process is restarted. This will blind an attacker as he has one second to disable every javascript file in your system which is impossible.

   */

   setInterval(function() {
   // check for existence of other scripts. This part will go in all other files to check for this file aswell. 
   var mainExists = document.getElementById("mainjs"); 
   if(mainExists) {
   }else{ location.reload();};
   //Check meta tag 1 for content changes. meta1 will always be 0. This you do for each meta on the page to ensure content credibility. No one will change a meta and get away with it. Addition of a meta in spot 10, say a meta after the id="meta10" should also be covered as below.
   var x = document.getElementsByTagName("meta")[0];
   var p = x.getAttribute("name");
   var s = x.getAttribute("content");
   if (p != 'description') {
   location.reload();
   }
   if ( s != 'Proper mitigation against script kiddies via Javascript') {
   location.reload();
   }
   // This will prevent a meta tag after this meta tag @ id="meta1". This prevents new meta tags from being added to your pages. This can be used for scripts or any tag you feel is needed to do integrity check on like inputs and scripts. (Yet again. It is not a replacement for headers to be added. Add your headers aswell!)
   var lastMeta = document.getElementsByTagName("meta")[1];
   if (lastMeta) {
   location.reload();
   }
   }, 1 * 1000); // 1 * 1000 milsec

style.css

Dies soll nur zeigen, dass es auch für alle Dateien und Tags funktioniert

   #heading {
   background-color:red;
   }

Wenn Sie alle diese Dateien zusammenfügen und das Beispiel erstellen, sehen Sie die Funktion dieser Kennzahl. Dies verhindert einige unvorhergesehene Injektionen, wenn Sie sie auf allen wichtigen Elementen in Ihrer Indexdatei korrekt implementieren, insbesondere wenn Sie mit PHP arbeiten.

Warum ich mich für das Neuladen entschieden habe, anstatt zum normalen Wert pro Attribut zurückzukehren, ist die Tatsache, dass einige Angreifer möglicherweise einen anderen Teil der Website bereits konfiguriert und bereit haben und dadurch die Codemenge verringert wird. Durch das Nachladen wird die harte Arbeit des Angreifers beseitigt und er wird wahrscheinlich an einem leichteren Ort spielen.

Noch ein Hinweis: Dies könnte zu viel Code werden. Halten Sie ihn daher sauber und fügen Sie Definitionen hinzu, wo sie hingehören, um Änderungen in Zukunft zu vereinfachen. Stellen Sie die Sekunden auch auf den von Ihnen bevorzugten Wert ein, da 1-Sekunden-Intervalle auf großen Seiten drastische Auswirkungen auf ältere Computer haben können, die Ihre Besucher möglicherweise verwenden


das ... das ist kein guter Ansatz.
RozzA
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.