mmofacts.com

ALLE Daten die vom User kommen sind falsch

gepostet vor 18 Jahre, 1 Monat von Mudder
Aus aktuellem Anlass möchte ich noch einmal darauf aufmerksam machen und allen Unwissenden eine kleine Erklärung anbieten.

Leider kontrollieren viele BGs bestenfalls die Zeichenlänge von Formfeldern ob das Passwort auch wirklich mindestens 6 Zeichen lang ist. Doch Werte und Gültigkeit von GET-Variablen (URL) oder die Gültigkeit von Formularen finden bei vielen den freien Weg ins Script. Ich möchte daher ein paar Beispiele auflisten und ein paar Gegenmittel präsentieren.

GET-Variablen aus der Adressleiste
Die wohl einfachste Möglichkeit Werte zu ändern ist die Adressleiste des Browsers. Dies kann z.B. eine geänderte Gebäude-ID im Baumenü sein, eine SQL-Injection wo mal eben ein paar neue Datenbankbefehle übermittelt werden oder gar eine geänderte UserID.

Geänderte Werte
Oftmals findet keine Kontrolle statt ob das Schiff oder das Gebäude überhaupt gebaut werden können. Man ändert "buildingid=12" mal eben auf "buildingid=21" und schon baut man etwas ganz anderes. Wenn eine Kontrolle des Variablenwertes stattfindet, dann kontrollieren viele nur ob es sich um eine Zahl handelt, doch viele prüfen nicht ob das Gebäude schon erforscht ist oder ob die Ressourcen vorhanden sind (siehe auch "geänderte Formulare").

SQL-Injections
Dank "magic_quotes" kommt diese Sicherheitslücke immer seltener vor. Viele User versuchen immer wieder Datenbankbefehle an Variablen zu hängen. Man sollte generell alle Variablen auf die Werte prüfen doch grade bei direkten SQL-Eingaben sollte man diese vorher nochmal z.B. mittels "mysql_escape_string() bearbeiten und sichern.

Userkontrolle
Trotz Sessions finden sich noch immer Spiele welche die Userkontrolle z.B. mittels "Userhashes" verwalten. Auch wenn die Codes nur temporär gültig sind so gibt es immerwieder Hacks, da unwissende User in Chats Links (inkl. Code) ausplaudern, welche andere nutzen um z.B. Ressourcen zu verschwenden, Schiffsbewegungen zu initiieren oder sich gar ganz in den Account zu schleichen.
Solche Systeme sollten ggfl. nochmal genaustens kontrolliert und ggfl. überarbeitet werden. Wichtigste Punkte sind aber auf jedenfall eine IP-Kontrolle des Userhashes um Diebstähle (seien sie auch nur von kurzer Dauer) zu vermeiden.



Formulare und POST-Variablen
Neben den "offenen" GET-Variablen gibts aber auch noch POST-Variablen welche manipuliert werden können. Die normale Kontrolle der Usereingaben findet zwar weitestgehend überall statt doch man muss auch dringend Werte Kontrollieren welche nicht vom User eingegeben werden können.

Geänderte Formulare
Dank simpler Tools wie z.B. dem Web Developer (einem Firefox-Plugin, der übrigends sehr zu empfehlen ist) ist es sehr einfach versteckte Formularfelder sichtbar zu machen oder disabled'te Felder zu aktivieren. Bei Formularübermittlungen solltet Ihr euch also nicht darauf verlassen, dass die Werte eines Radio-Feldes korrekt sind, nur weil Ihr bei der Ausgabe die Felder deaktiviert habt wo zu wenig Ressourcen vorhanden sind. Auch hidden-Felder können leicht geändert werden und z.B. Userhash's oder IDs sind ein lohnendes Ziel für Cheater und Buguser. Dies gilt auch für Javascriptbedingte Werte bzw. Kontrollen!

Wertekontrolle der Eingaben
Viele überprüfen bei Variablen nur ob es sich um eine Ganzzahl handelt oder ob das Passwort länger als 6 Zeichen ist. Man sollte bei Zahlen aber wirklich einen genauen Wertebereich prüfen (von bis) und auch Texten ein bestimmten Spielraum geben (Min Max). Select-Variablen und Co sollten ebenfalls überprüft werden - sowohl ob sie vom User ausgewählt werden können bzw. ob die Werte überhaupt exestieren.




Ich wills nochmal sagen. ALLE Daten die vom User an den Server geschickt werden sind potenzielle Fälschungen und müssen überwacht werden. Bei meinen Recherchen zu meinem Cheater-Bericht haben mir viele geschrieben welche solche Lücken in "Ihrem" BG entdeckt haben und diese nutzen. Ihr solltet daher alle Variablen (vor allem GET) genaustens prüfen. Und zwar sowohl auf den übertragenen Wert und ob die Aktion vom User auch ausgeführt werden kann (geänderte Gebäude-ID im Baumenü).

Wie Ihr die Kontrolle vornehmt ist natürlich Euch überlassen. Ich persönlich lasse Werte z.B. mit einer eigenen form_check()-Funktion überprüfen
	function getform($name, $type, $start = 0, $ende = 50000, $from = "post") {

if ($from == "post") $var = $_POST[$name];
else if ($from == "get") $var = $_GET[$name];
else return false;

switch($typ) {
case "text":
case "string":
if (self::strlen_utf8($var) >= $min && self::strlen_utf8($var) <= $max) return $var;
else return false;
break;
case "int":
case "integer":
$var = intval($var);
if ($var >= $min && $var <= $max) return $var;
else return false;
break;
case "float":
$var = str_replace(",", ".", $var);
$var = round($var, 2);
if ($var >= $min && $var <= $max) return $var;
else return false;
break;
case "email":
if(!eregi("^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$", $var)) return false;
else return $var;
break;
case "date":
if(!eregi("^[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{2,4}$", $var)) return false;
else return $var;
break;
default:
return trim($var);
}
}

formcheck("buildingid", "int", 1, 80);
formcheck("message", "text", 1, 500);



Mit Hilfe dieser Funktion hole ich mir Variablen aus POST oder GET und prüfe diese auf den vorgegebenen Wert. Entsprechend wird die Variable zurückgegeben oder per false ein Fehler ausgegeben.
Ob Ihr nun meine Methode oder eine eigene Funktion entwicklet ist natürlich jedem selber überlassen. Doch ihr müsst die Variablen wirklich kontrollieren!!
gepostet vor 18 Jahre, 1 Monat von Chojin
Ein lustiger Anfängerfehler, den ich dieses wochenende zum 3. mal in einem Spiel angetroffen habe ist übrigens, dass man bei einigen Usereingabemasken (speziel rohstofftransport, einheiten überführung, etc) negative Werte eintragen kann und so ein unbekannter Empfänger zum ahnungslosen, großzügigen Spender wird.

Das sind so Fehler die allerdings sofort auffallen und im normalen Betrieb meistens ausgebügelt werden. Man sollte grundsätzlich alle Daten hinterfragen die der Spieler in irgendeiner weise übermittelt.

reg4rds
chojin
gepostet vor 18 Jahre, 1 Monat von Kampfhoernchen
Ich löse den Zugriff auf externe Daten mit einer Klasse (noch nicht ganz fertig):
 


class RemoteData{

function RemoteData(){

}


function getString($varname){
return (string)$_REQUEST[$varname];
}

function geteString($varname){
return mysql_real_escape_string($_REQUEST[$varname]);
}

function getInt($varname){
return intval($_REQUEST[$varname]);
}

function getDecimal($varname){
return floatval($_REQUEST[$varname]);
}

function getFile($varname){
echo 'TODOOOO';
}

function getArray($varname){
if(is_array($_REQUEST[$varname]))
return $_REQUEST[$varname];
else return array();
}

function exists($varname){
return isset($_REQUEST[$varname]);
}

function allExists($varnames){
foreach($varnames as $varname){
if(!$this->exists($varname)){
return false;
}
}
return true;
}

function isClear($varname, $clear=''){
if($clear == $_REQUEST[$varname])
return true;
else
return false;
}

}


Sollte ja selbsterklärend sein.
gepostet vor 18 Jahre, 1 Monat von woodworker
Original von Mudder
SQL-Injections
Dank "magic_quotes" kommt diese Sicherheitslücke immer seltener vor. Viele User versuchen immer wieder Datenbankbefehle an Variablen zu hängen. Man sollte generell alle Variablen auf die Werte prüfen doch grade bei direkten SQL-Eingaben sollte man diese vorher nochmal z.B. mittels "mysql_escape_string() bearbeiten und sichern.


Ohh gott wie ich magic_quotes hasse - zum glück werden die für immer verschwinden - sind schon aus dem source für php6 entfernt
man sollte immer selber escapen - oder für Faule prepared statements nutzen, ist zwar etwas übertrieben aber auch möglich.
und wenn man nen neueres mysql hat immer mysql_real_escape_string nehmen
gepostet vor 18 Jahre, 1 Monat von Crafty-Catcher
Original von Chojin
Ein lustiger Anfängerfehler, den ich dieses wochenende zum 3. mal in einem Spiel angetroffen habe ist übrigens, dass man bei einigen Usereingabemasken (speziel rohstofftransport, einheiten überführung, etc) negative Werte eintragen kann und so ein unbekannter Empfänger zum ahnungslosen, großzügigen Spender wird.


Genau aus diesem Grund braucht man die Funktion abs() die aus diesen negativen Werten Absolut Werte bildet und das den verhinderten "Cheater" teuer zu stehen kommen lassen, nur leider versuchen die es erst mit niedrigen Zahlen und dann mit ganz großen
gepostet vor 18 Jahre, 1 Monat von BLUESCREEN
Original von Mudder
SQL-Injections
(...) nochmal z.B. mittels "mysql_escape_string() bearbeiten und sichern.

Doppeltes Escapen kann nicht gut sein
gepostet vor 18 Jahre, 1 Monat von woodworker
Original von BLUESCREEN
Original von Mudder
SQL-Injections
(...) nochmal z.B. mittels "mysql_escape_string() bearbeiten und sichern.

Doppeltes Escapen kann nicht gut sein

jap wie gesagt ich hasse magic_quotes - genau deswegen
gepostet vor 18 Jahre, 1 Monat von mifritscher
was noch gern gemacht wird ist es zu vergessen Zahlenwerte zu intvalen und dann in SQL-Queries wie SELECT * FROM table WHERE ID=$d zu setzen.
escapen hilft hier nichts, weil auch $d="ID" schon bös genug sein kann...
gepostet vor 18 Jahre, 1 Monat von knalli
Original von woodworker
Original von BLUESCREEN
Original von Mudder
SQL-Injections
(...) nochmal z.B. mittels "mysql_escape_string() bearbeiten und sichern.

Doppeltes Escapen kann nicht gut sein

jap wie gesagt ich hasse magic_quotes - genau deswegen

Ähm, wenn man konsequent ein Schema nutzt? Solang man _weiß_ was man tut, ist es nicht gefährlich. Ich muss in C nichts casten, wenn ich weiß, dass der Compiler es automatisch tut - an anderen Stellen muss ich das tun.

Was ich damit sagen will: Wenn man weiß, warum man MQ anwendet und "wo", dann ist das mE legitim. Nicht korrekt ist aber, jetzt die Frage in den Raum zu werfen, was die Escapetaste mit PHP zu hätte...
gepostet vor 18 Jahre, 1 Monat von Kampfhoernchen
Original von mifritscher
was noch gern gemacht wird ist es zu vergessen Zahlenwerte zu intvalen und dann in SQL-Queries wie SELECT * FROM table WHERE ID=$d zu setzen.
escapen hilft hier nichts, weil auch $d="ID" schon bös genug sein kann...


Und deswegen bastelt man da ein Anführungszeichen außen rum. Mit meiner get_int()-Funktion kann da sowieso kein String mehr stehen.
gepostet vor 18 Jahre, 1 Monat von Mudder
Ich bin schon ein wenig enttäuscht..
statt das sich grade mal "kleine" zu Wort melden und darauf eingehen kommen die "grossen" an und rivalisieren um die beste Validierungsmethode.

Ich hab das hier nich geschrieben weil ich meine Funktion preisgeben wollte sondern weil min. 1/3 aller BGs keine wirkliche Sicherung von Variablen vornehmen und darunter sind auch mehrere grosse BGs wo man das garnicht erwarten würde.
gepostet vor 18 Jahre, 1 Monat von TheUndeadable
@woodworker: Leider ist das verlinkte PDF in englischer Sprache und verfehlt die Zielgruppe. Ich muss dennoch sagen, dass der Inhalt sehr qualitativ hochwertig und wahrscheinlich sogar nahezu komplett bin.

EDIT auf nachfolgenden Post:
Mit Zielgruppe meine ich den jungen Browsergameprogrammierer, der gerade erst mit PHP anfängt. Er hat erst wenige technische Texte auf englisch gelesen und die Spracherfassung läuft in der deutschen Sprache einfacher ab als in der englischen.
EDIT Ende.

Ich bin Mudder aber sehr dankbar, dass er eine kurze Auflistung so mancher Problemfälle postet. Mit den Magic Quotes bin ich zwar nicht auch einer Meinung, aber ohne dieses würde es bei der PHP-Sicherheit noch viel grauseliger aussehen.

Ich persönlich würde übrigens statt auf die berühmten:

$szQuery = "SELECT * FROM table WHERE userid=" . intval ( $userid );

lieber auf die Parameter-Darstellung der PDO setzen.

$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);

// insert one row
$name = 'one';
$value = 1;
$stmt->execute();

Denn diese sind garantiert sicher, da sich dann das PHP-Framework um das Escapen und Quoting kümmert und zwar abhängig vom verwendeten Datenbanktyp.

http://www.php.net/PDO
gepostet vor 18 Jahre, 1 Monat von woodworker
zielgrupper verfehlt?
also ich kenne in meinem bekantenkreis keinen der kein englisch kann
sogar meine mutter kann englisch

nur so als anmerkung ich/wir/sie bin/sind/ist ausm Ostn
gepostet vor 18 Jahre, 1 Monat von Mudder
Die quote()-Funktion von PDO ist sicher eine der besten Methoden für Queries und sollte auf jeden Fall verwendet werden ..
.. sofern man mit PHP5 (und entsprechend mit PDO) arbeitet.
gepostet vor 18 Jahre, 1 Monat von Macavity
ich weiß nicht aber ich mach mir bei meinen games jetzt nicht den Monsteraufwand nur um sicherzustellen das alles hundertpro korrekt läuft, wenn ich merke das jemand cheatet fliegt er. damit beuge ich auch gleich vor dass andere das Gefühl bekommen cheaten zu wollen..
gepostet vor 18 Jahre, 1 Monat von woodworker
"Bevorzugt englisch, da höhere Qualität"

naja stimmt nicht ganz

"Bevorzugt höhere Qualität auch wenn englisch"
gepostet vor 18 Jahre, 1 Monat von Mudder
Ihr könnt nun sicher ewig über die Umfragewerte streiten, doch der Bericht ist wie du selber sagtest nur eine Diavorlage für eine Konferenz. Was da draufsteht kann man einfach nur als Stichpunkte betrachten und eben nicht als Sicherheitsbericht mit Lösungsvorschlägen. Der Autor hat sein Vortrag gehalten und dazu die Bilder gezeigt wo entsprechend zum Vortrag die Punkte und Beispiele draufstehen.

Und so ein Bericht ist vielleicht für ein erfahrenen Programmierer interessant weil er aus den wenigen Wörtern noch erkennen kann worum es geht doch viele wissen nichtmal was der Unterschied zwischen $_GET und $_REQUEST ist. Und das "Profis" wie Ihr Eure Variablen prüft und sichert kann sich wohl jeder denken.. bloss da bringts nem "Neuling" nix wenn du mit nem englischen Dia-Vortrag ankommst, wenn in seinem Spiel mit nur einer GET-Variable mal eben die Rohstoffe aufgefrischt werden können.

Auf diese Diskussion antworten