Login Script
Thomas
- meinung
0 davidp2 Jens Holzkämper0 Bobby0 Jens Holzkämper0 Alexander (HH)
2 Vinzenz Mai0 Vinzenz Mai0 Thomas
1 Alexander (HH)0 Auge
Hallo zusammen,
Ich habe mal versucht mit Ajax ein Login Script zu erstellen. Das ist mir mir meiner Meinung nach auch einigermassen gut gelungen. Da es so etwa mein erstes grosses Script in Ajax ist frage ich hier mal nach. Ist mein Script so sinnvoll, sicher etc..
Ein paar werden sich vieleicht Fragen warum Ajax... Ich wollte einen Login der auch schön ausschaut und mit Ajax lassen sich Ladegrafiken etc meiner Meinung nach am besten verwirklichen.
<?php
session_start();
if(isset($_POST['name']))
{
if(isset($_POST['ajax']))
{
$pw = md5($_POST['pw']);
$name = $_POST['name'];
$con = mysql_connect("localhost","Benutzername","Passwort");
mysql_select_db("Datenbank",$con);
$sql="SELECT userid FROM user WHERE username='".$name."' AND passwort='".$pw."' LIMIT 1";
$result= mysql_query($sql);
if(mysql_num_rows($result) == 1)
{
$user=mysql_fetch_assoc($result);
$userid = $user['userid'];
$sql="UPDATE user SET session='".session_id()."' WHERE userid=".$userid;
mysql_query($sql);
echo "1";
}
else
{
echo "2";
}
}
elseif(!isset($_POST['ajax']))
{
$pw = md5($_POST['password']);
$name = $_POST['username'];
$con = mysql_connect("localhost","Benutzername","Passwort");
mysql_select_db("Datenbank",$con);
$sql="SELECT userid FROM user WHERE username='".$name."' AND passwort='".$pw."' LIMIT 1";
$result= mysql_query($sql);
if(mysql_num_rows($result) == 1)
{
$user=mysql_fetch_assoc($result);
$userid = $user['userid'];
$sql="UPDATE user SET session='".session_id()."' WHERE userid=".$userid;
mysql_query($sql);
Header("Location: home.php");
}
else
{
Header("Location: index.php?login=false");
}
}
exit;
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="robots" content="noindex,nofollow" />
<link rel="stylesheet" href="login.css" type="text/css" media="screen" />
<title>Login</title>
<script language="javascript" type="text/javascript">
<!--
function unsu() {
login();
return false;
}
function handle(result) {
if(result == 1) {
document.getElementById('messages').innerHTML = "<div id='ajax_accept'> Login erfolgreich...</div>"
setTimeout("window.location = 'home.php';", 1500);
}
else {
document.getElementById('messages').innerHTML = "<div id='ajax_error'> Überprüfen Sie ihre Angaben...</div>"
}
}
function login() {
var data = "name=" + document.getElementById('username12').value + "&pw=" + document.getElementById('passwort').value + "&ajax=ja";
var httpObject = null;
document.getElementById('messages').innerHTML = "<div id='ajax_load'>Überprüfe Daten...</div>";
if (window.XMLHttpRequest)
{
httpObject = new XMLHttpRequest();
}
else if (window.ActiveXObject)
{
try
{
httpObject = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e)
{
try
{
httpObject = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e)
{
httpObject = null;
}
}
}
if (httpObject != null)
{
httpObject.onreadystatechange = auswerten;
httpObject.open('POST', "index.php", true);
httpObject.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
httpObject.setRequestHeader("Content-length", data.length);
httpObject.setRequestHeader("Connection", "close");
httpObject.send(data);
}
function auswerten() {
if(httpObject.readyState == 4)
{
if(httpObject.status == 200)
{
result = httpObject.responseText;
setTimeout("handle(result)", 1500);
return false;
}
}
}
}
//-->
</script>
</head>
<body>
<div id="abstand"></div>
<div id="login">
<img src="img/login_logo.png" alt="Login" style="width:489px;height:164px" />
<form method="post" action="index.php" class="png">
<label for="username" id="username">
<span>Benutzername: </span>
<input type="text" name="username" id="username12" onfocus="change('user');" onblur="unchange('user');" />
</label>
<label for="password" id="password">
<span>Kennwort: </span>
<input type="password" name="password" id="passwort" onfocus="change('pw');" onblur="unchange('pw');" />
</label>
<div id="messages">
~~~~~~php
<?php
if(isset($_GET['login']))
{
if($_GET['login'] == "false")
{
echo "<div id='ajax_error'> Überprüfen Sie ihre Angaben...</div>";
}
}
?>
~~~~~~html
</div>
<input type="submit" value="Login" class="button" onclick="return unsu();" />
</form>
</div>
</body>
</html>
Vielen Dank im Voraus
Thomas
Hallo Thomas!
Also ich find das Skript eh gut und sicher ist es ja auch, der PHP-Code ist grundsätzlich immer geschützt. Aber die eigentliche Seite (nach dem erfolgreichen Login) könnte vielleicht noch schneller angezeigt werden z.B. mit include("home.php") (wenn möglich).
aber sonst, gute Arbeit! Und danke, jetzt kann ich auch AJAX (hab mir vor langer Zeit ein AJAX-Email Beispiel angeschaut und einfach nicht durchgeblick...)
lg davidp
Tach,
$pw = md5($_POST['pw']);
MD5 sollte als gebrochen bewertet und nicht mehr für neue Projekte genutzt werden, schon gar nicht ohne Salt.
$name = $_POST['name'];
$sql="SELECT userid FROM user WHERE username='".$name."' AND passwort='".$pw."' LIMIT 1";
http://xkcd.com/327/, jegliche vom Client stammende Kommunikation ist immer als bösartiger Angriff zu betrachten, bis das Gegenteil bewiesen ist.
mfg
Woodfighter
Moin
MD5 sollte als gebrochen bewertet und nicht mehr für neue Projekte genutzt werden, schon gar nicht ohne Salt.
Was ist die bessere leicht zu handelnde Alternative? SHA?
Gruß Bobby
Tach,
Was ist die bessere leicht zu handelnde Alternative? SHA?
jup, das sollte auch in PHP enthalten sein. Für komplexere Aufgaben als das Hashen von Paßwörtern sollte man aber vermutlich gleich einen der SHA2-Algorithmen wählen.
mfg
Woodfighter
Was ist die bessere leicht zu handelnde Alternative? SHA?
jup, das sollte auch in PHP enthalten sein. Für komplexere Aufgaben als das Hashen von Paßwörtern sollte man aber vermutlich gleich einen der SHA2-Algorithmen wählen.
???
mfg Beat;
Tach,
Was ist die bessere leicht zu handelnde Alternative? SHA?
jup, das sollte auch in PHP enthalten sein. Für komplexere Aufgaben als das Hashen von Paßwörtern sollte man aber vermutlich gleich einen der SHA2-Algorithmen wählen.???
was möchtest du hinterfragen?
mfg
Woodfighter
Was ist die bessere leicht zu handelnde Alternative? SHA?
jup, das sollte auch in PHP enthalten sein. Für komplexere Aufgaben als das Hashen von Paßwörtern sollte man aber vermutlich gleich einen der SHA2-Algorithmen wählen.???
was möchtest du hinterfragen?
Meines Wissens dienen alle SHA Versionen dem Hashen. Unterschiede bestehen in der Schlüssellänge. Nicht die Komplexität der Aufgabe, die bleibt nämlich für alle Versionen gleich, sondern der erforderte Schutz gegen mögliche Kollision spielt hier eine Rolle bei der Wahl, falls man eine hat.
mfg Beat
Tach,
Meines Wissens dienen alle SHA Versionen dem Hashen. Unterschiede bestehen in der Schlüssellänge. Nicht die Komplexität der Aufgabe, die bleibt nämlich für alle Versionen gleich, sondern der erforderte Schutz gegen mögliche Kollision spielt hier eine Rolle bei der Wahl, falls man eine hat.
das meinte ich, das Hashen eines Paßwortes dient ja nur dazu das Originalpaßwort zu verschleiern, der Hash beispielsweise einer digitalen Signatur ist da schon etwas komplexeres.
mfg
Woodfighter
Moin
ich hab dazu ein Class-Script gefunden. Ist dies geeignet?
if (!defined('__PHP_SHA256_NANO_'))
{
define('__PHP_SHA256_NANO_', true);
class shaHelper
{
function shaHelper()
{
// nothing to construct here...
}
// Do the SHA-256 Padding routine (make input a multiple of 512 bits)
function char_pad($str)
{
$tmpStr = $str;
$l = strlen($tmpStr)*8; // # of bits from input string
$tmpStr .= "\x80"; // append the "1" bit followed by 7 0's
$k = (512 - (($l + 8 + 64) % 512)) / 8; // # of 0 bytes to append
$k += 4; // PHP String's will never exceed (2^31)-1, so 1st 32bits of
// the 64-bit value representing $l can be all 0's
for ($x = 0; $x < $k; $x++)
$tmpStr .= "\0";
// append the last 32-bits representing the # of bits from input string ($l)
$tmpStr .= chr((($l>>24) & 0xFF));
$tmpStr .= chr((($l>>16) & 0xFF));
$tmpStr .= chr((($l>>8) & 0xFF));
$tmpStr .= chr(($l & 0xFF));
return $tmpStr;
}
// Here are the bitwise and custom functions as defined in FIPS180-2 Standard
function addmod2n($x, $y, $n = 4294967296) // Z = (X + Y) mod 2^32
{
$mask = 0x80000000;
if ($x < 0)
{
$x &= 0x7FFFFFFF;
$x = (float)$x + $mask;
}
if ($y < 0)
{
$y &= 0x7FFFFFFF;
$y = (float)$y + $mask;
}
$r = $x + $y;
if ($r >= $n)
{
while ($r >= $n)
$r -= $n;
}
return (int)$r;
}
// Logical bitwise right shift (PHP default is arithmetic shift)
function SHR($x, $n) // x >> n
{
if ($n >= 32) // impose some limits to keep it 32-bit
return (int)0;
if ($n <= 0)
return (int)$x;
$mask = 0x40000000;
if ($x < 0)
{
$x &= 0x7FFFFFFF;
$mask = $mask >> ($n-1);
return ($x >> $n) | $mask;
}
return (int)$x >> (int)$n;
}
function ROTR($x, $n) { return (int)($this->SHR($x, $n) | ($x << (32-$n))); }
function Ch($x, $y, $z) { return ($x & $y) ^ ((~$x) & $z); }
function Maj($x, $y, $z) { return ($x & $y) ^ ($x & $z) ^ ($y & $z); }
function Sigma0($x) { return (int) ($this->ROTR($x, 2)^$this->ROTR($x, 13)^$this->ROTR($x, 22)); }
function Sigma1($x) { return (int) ($this->ROTR($x, 6)^$this->ROTR($x, 11)^$this->ROTR($x, 25)); }
function sigma_0($x) { return (int) ($this->ROTR($x, 7)^$this->ROTR($x, 18)^$this->SHR($x, 3)); }
function sigma_1($x) { return (int) ($this->ROTR($x, 17)^$this->ROTR($x, 19)^$this->SHR($x, 10)); }
/*
* Custom functions to provide PHP support
*/
// split a byte-string into integer array values
function int_split($input)
{
$l = strlen($input);
if ($l <= 0) // right...
return (int)0;
if (($l % 4) != 0) // invalid input
return false;
for ($i = 0; $i < $l; $i += 4)
{
$int_build = (ord($input[$i]) << 24);
$int_build += (ord($input[$i+1]) << 16);
$int_build += (ord($input[$i+2]) << 8);
$int_build += (ord($input[$i+3]));
$result[] = $int_build;
}
return $result;
}
}
// Compatability with older versions of PHP < 5
if (!function_exists('str_split'))
{
function str_split($string, $split_length = 1)
{
$sign = (($split_length < 0) ? -1 : 1);
$strlen = strlen($string);
$split_length = abs($split_length);
if (($split_length == 0) || ($strlen == 0))
{
$result = false;
}
elseif ($split_length >= $strlen)
{
$result[] = $string;
}
else
{
$length = $split_length;
for ($i = 0; $i < $strlen; $i++)
{
$i = (($sign < 0) ? $i + $length : $i);
$result[] = substr($string, $sign*$i, $length);
$i--;
$i = (($sign < 0) ? $i : $i + $length);
if (($i + $split_length) > ($strlen))
{
$length = $strlen - ($i + 1);
}
else
{
$length = $split_length;
}
}
}
return $result;
}
}
/*
* Main routine called from an application using this include.
*
* General usage:
* require_once(sha256.inc.php);
* $hashstr = sha256("abc");
*
* Note:
* PHP Strings are limitd to (2^31)-1, so it is not worth it to
* check for input strings > 2^64 as the FIPS180-2 defines.
*/
function sha256($str, $ig_func = false)
{
unset($binStr); // binary representation of input string
unset($hexStr); // 256-bit message digest in readable hex format
// check for php 5.1.2's internal sha256 function, ignore if ig_func is true
if ($ig_func == false)
if (function_exists("hash"))
return hash("sha256", $str, false);
/*
* Use PHP Implementation of SHA-256 if no other library is available
* - This method is much slower, but adds an additional level of fault tolerance
*/
$sh = new shaHelper();
// SHA-256 Constants
// sequence of sixty-four constant 32-bit words representing the first thirty-two bits
// of the fractional parts of the cube roots of the first sixtyfour prime numbers.
$K = array((int)0x428a2f98, (int)0x71374491, (int)0xb5c0fbcf, (int)0xe9b5dba5,
(int)0x3956c25b, (int)0x59f111f1, (int)0x923f82a4, (int)0xab1c5ed5,
(int)0xd807aa98, (int)0x12835b01, (int)0x243185be, (int)0x550c7dc3,
(int)0x72be5d74, (int)0x80deb1fe, (int)0x9bdc06a7, (int)0xc19bf174,
(int)0xe49b69c1, (int)0xefbe4786, (int)0x0fc19dc6, (int)0x240ca1cc,
(int)0x2de92c6f, (int)0x4a7484aa, (int)0x5cb0a9dc, (int)0x76f988da,
(int)0x983e5152, (int)0xa831c66d, (int)0xb00327c8, (int)0xbf597fc7,
(int)0xc6e00bf3, (int)0xd5a79147, (int)0x06ca6351, (int)0x14292967,
(int)0x27b70a85, (int)0x2e1b2138, (int)0x4d2c6dfc, (int)0x53380d13,
(int)0x650a7354, (int)0x766a0abb, (int)0x81c2c92e, (int)0x92722c85,
(int)0xa2bfe8a1, (int)0xa81a664b, (int)0xc24b8b70, (int)0xc76c51a3,
(int)0xd192e819, (int)0xd6990624, (int)0xf40e3585, (int)0x106aa070,
(int)0x19a4c116, (int)0x1e376c08, (int)0x2748774c, (int)0x34b0bcb5,
(int)0x391c0cb3, (int)0x4ed8aa4a, (int)0x5b9cca4f, (int)0x682e6ff3,
(int)0x748f82ee, (int)0x78a5636f, (int)0x84c87814, (int)0x8cc70208,
(int)0x90befffa, (int)0xa4506ceb, (int)0xbef9a3f7, (int)0xc67178f2);
// Pre-processing: Padding the string
$binStr = $sh->char_pad($str);
// Parsing the Padded Message (Break into N 512-bit blocks)
$M = str_split($binStr, 64);
// Set the initial hash values
$h[0] = (int)0x6a09e667;
$h[1] = (int)0xbb67ae85;
$h[2] = (int)0x3c6ef372;
$h[3] = (int)0xa54ff53a;
$h[4] = (int)0x510e527f;
$h[5] = (int)0x9b05688c;
$h[6] = (int)0x1f83d9ab;
$h[7] = (int)0x5be0cd19;
// loop through message blocks and compute hash. ( For i=1 to N : )
for ($i = 0; $i < count($M); $i++)
{
// Break input block into 16 32-bit words (message schedule prep)
$MI = $sh->int_split($M[$i]);
// Initialize working variables
$_a = (int)$h[0];
$_b = (int)$h[1];
$_c = (int)$h[2];
$_d = (int)$h[3];
$_e = (int)$h[4];
$_f = (int)$h[5];
$_g = (int)$h[6];
$_h = (int)$h[7];
unset($_s0);
unset($_s1);
unset($_T1);
unset($_T2);
$W = array();
// Compute the hash and update
for ($t = 0; $t < 16; $t++)
{
// Prepare the first 16 message schedule values as we loop
$W[$t] = $MI[$t];
// Compute hash
$_T1 = $sh->addmod2n($sh->addmod2n($sh->addmod2n($sh->addmod2n($_h, $sh->Sigma1($_e)), $sh->Ch($_e, $_f, $_g)), $K[$t]), $W[$t]);
$_T2 = $sh->addmod2n($sh->Sigma0($_a), $sh->Maj($_a, $_b, $_c));
// Update working variables
$_h = $_g; $_g = $_f; $_f = $_e; $_e = $sh->addmod2n($_d, $_T1);
$_d = $_c; $_c = $_b; $_b = $_a; $_a = $sh->addmod2n($_T1, $_T2);
}
for (; $t < 64; $t++)
{
// Continue building the message schedule as we loop
$_s0 = $W[($t+1)&0x0F];
$_s0 = $sh->sigma_0($_s0);
$_s1 = $W[($t+14)&0x0F];
$_s1 = $sh->sigma_1($_s1);
$W[$t&0xF] = $sh->addmod2n($sh->addmod2n($sh->addmod2n($W[$t&0xF], $_s0), $_s1), $W[($t+9)&0x0F]);
// Compute hash
$_T1 = $sh->addmod2n($sh->addmod2n($sh->addmod2n($sh->addmod2n($_h, $sh->Sigma1($_e)), $sh->Ch($_e, $_f, $_g)), $K[$t]), $W[$t&0xF]);
$_T2 = $sh->addmod2n($sh->Sigma0($_a), $sh->Maj($_a, $_b, $_c));
// Update working variables
$_h = $_g; $_g = $_f; $_f = $_e; $_e = $sh->addmod2n($_d, $_T1);
$_d = $_c; $_c = $_b; $_b = $_a; $_a = $sh->addmod2n($_T1, $_T2);
}
$h[0] = $sh->addmod2n($h[0], $_a);
$h[1] = $sh->addmod2n($h[1], $_b);
$h[2] = $sh->addmod2n($h[2], $_c);
$h[3] = $sh->addmod2n($h[3], $_d);
$h[4] = $sh->addmod2n($h[4], $_e);
$h[5] = $sh->addmod2n($h[5], $_f);
$h[6] = $sh->addmod2n($h[6], $_g);
$h[7] = $sh->addmod2n($h[7], $_h);
}
// Convert the 32-bit words into human readable hexadecimal format.
$hexStr = sprintf("%08x%08x%08x%08x%08x%08x%08x%08x", $h[0], $h[1], $h[2], $h[3], $h[4], $h[5], $h[6], $h[7]);
return $hexStr;
}
} // __PHP_SHA256_NANO_
Gruß Bobby
Hallo,
ich hab dazu ein Class-Script gefunden. Ist dies geeignet?
Kennst Du hash()? Schau Dir die Liste der unterstützten Algorithmen an (ab PHP 5.1.2, d.h. sollte zur Verfügung stehen, falls es der Provider nicht deaktiviert hat).
Freundliche Grüße
Vinzenz
Moin Moin!
Was ist die bessere leicht zu handelnde Alternative? SHA?
Zum Beispiel. Und auf jeden Fall gehört ein Salt mit in die Hash-Berechnung, sonst ist das System anfällig für Rainbow-Tabellen.
Und mal so am Rande, weil immer wieder gern gebaut: Exponenziell ansteigende Sperrzeiten oder gar vollständiges Sperren eines Benutzeraccounts bei mehreren falschen Logins ist eine wunderbare Vorgabe für DoS-Angriffe. Einfach ein paar Mal mit einem Wörterbuch über die Login-Seite rennen und schon sind 99% aller User dauerhaft ausgesperrt.
Alexander
Und mal so am Rande, weil immer wieder gern gebaut: Exponenziell ansteigende Sperrzeiten oder gar vollständiges Sperren eines Benutzeraccounts bei mehreren falschen Logins ist eine wunderbare Vorgabe für DoS-Angriffe. Einfach ein paar Mal mit einem Wörterbuch über die Login-Seite rennen und schon sind 99% aller User dauerhaft ausgesperrt.
Ich schicke mein Script nur mal 5 Sekunden schlafen.
mfg Beat
Moin Moin!
»» Und mal so am Rande, weil immer wieder gern gebaut: Exponenziell ansteigende Sperrzeiten oder gar vollständiges Sperren eines Benutzeraccounts bei mehreren falschen Logins ist eine wunderbare Vorgabe für DoS-Angriffe. Einfach ein paar Mal mit einem Wörterbuch über die Login-Seite rennen und schon sind 99% aller User dauerhaft ausgesperrt.
Ich schicke mein Script nur mal 5 Sekunden schlafen.
OK, laß mich mal spielen:
Ich bin böse auf Dich, weil mir Deine Socken absolut nicht gefallen und Du absolut nicht dazu zu bewegen bist, Dir Socken wie Pippi Langstrumpf anzuziehen. Also will ich Dich bei Deinen Kunden möglichst nachhaltig unbeliebt machen.
Ich merke, dass Dein Script anfängt zu trödeln, wenn ich mein Wörterbuch mit einem dummen Script Deinem Server sequenziell reindrücke.
Mein Angriffsrechner ist reichlich mit CPU, RAM und Internet-Bandbreite ausgestattet. Also schmeiß ich 10 weitere Zeilen in mein Script, zerteile das Wörterbuch in 1000 Teile, und lasse jeden Teil in einem eigenen Prozess auf Deinen Server einschlagen.
Dein Webserver darf jetzt nahezu parallel 1000 PHP-Aufrufe verdauen, entweder mit mod_php oder mit dem PHP-CGI. Vermutlich greift schon vorher irgendwo die Bremse, z.B. beim Apachen durch ServerLimit, MaxClients, oder
ThreadsPerChild. Und alle Prozesse bzw. Threads sind mit sleep() beschäftigt, statt weiter Requests zu beantworten. Dein Server ist tot (genauer: reagiert nicht mehr auf HTTP-Requests).
Du hast einen fähigen und flinken Provider, der meinen einen bösen Rechner an der unüblich hohen Last erkennt und den Zugiff auf Deinen Webserver per Firewall blockt. Oder Du richtest eine entsprechende Paketfilterregel auf Deinem Server ein. Dein Server lebt wieder.
Ich wechsle meine IP-Adresse und das Spiel beginnt von vorne. Dein Server ist wieder tot.
Mir gehen die IP-Adressen aus. Ich kaufe mir Zugriff auf ein Botnet und lasse den Angriff von ein paar tausend ungepatchten Windows-Gurken quer über die ganze Welt verteilt laufen, jeder mit einem tausendstel des Wörterbuchs, und so lange, bis ich ein paar Accounts geknackt habe. Dein Server ist tot.
Du bzw. Dein Provider muß tausende IP-Adressen sperren und sperrt damit auch einen Teil deiner Kunden aus. Ziel teilweise erreicht. Tut er das nicht, ist Dein Server tot. Ziel komplett erreicht.
Du bzw. Dein Provider muß also sperren, um den Server erreichbar zu halten, auch wenn er damit Kunden aussperrt. Ich kaufe bei irgendwelchen zwielichtigen Gestalten noch ein paar 10.000 Zombie-PCs dazu, die Deinen Server weiterhin zum Schlafen bewegen sollen.
Du / Dein Provider muß noch mehrere 10.000 IP-Adressen in die Blacklist eintragen und auch wieder austragen (dynamische IP-Adressen!), was die Firewall bzw. den Paketfilter oder wenigstens die Nerven ziemlich belastet.
Irgendwann ist das Maß voll und Du / Dein Provider blockiert ganze IP-Ranges, mit entsprechenden Kollateralschäden bei Deinen Kunden. Und trotzdem kommen noch immer genügend Anfragen durch, um Deinen Server im Koma zu halten -- oder aber der Server ist so abgeschottet, dass Deine Kunden auch nicht mehr darauf zugreifen können. Ziel erreicht.
Kurz bevor Du Dir im Astrid-Lindgren-Gedenk-Webshop 10 Paar Pippi-Langstrumpf-Socken bestellst, rät Dir ein Freund, das sleep() mal auszukommentieren, schon fällt der Angriff in sich zusammen.
Alexander
Kurz bevor Du Dir im Astrid-Lindgren-Gedenk-Webshop 10 Paar Pippi-Langstrumpf-Socken bestellst, rät Dir ein Freund, das sleep() mal auszukommentieren, schon fällt der Angriff in sich zusammen.
Also die Socken würden mich auf jeden Fall interessieren.
Ist es nicht so, dass du mit deiner Methode ja gar nicht darauf angewiesen bist, ob ich nun schlafe oder nicht?
Aber ich gebe dir recht, insofern, dass ich dich zu einem billigen Angriff verleite.
Nun aber die Frage nach dem geeigneten Rezept. Du machst eine Wörterbuchattacke. Ich schlafe nicht. Irgendwo gibt es auf jeden Fall einen Flaschenhals (Stichwort Filelocking)
Die Frage ist also welche Art von Angriff will ich abwehren. Deinen Angriff mit Zombiebots kann ich nicht abwehren. Es ist dir ja schliesslich egal, was ich für einen Output sende.
Was ich tun kann ist, abfragen gegen das Loggin Formular kontrollieren.
Nun logge ich. Ich logge IPs. Du sendest mir immer eine neue IP. Du hast so ziemlich viele Testmöglichkeiten, ohne dass ich mit dem Loggen irgenwo hin komme.
Indem ich allgemein unabhängig von der IP schlafe, verhindere ich das was ich kann: Angriffe gegen das Login Formular.
Andere Angriffsmöglichkeiten kann ich nicht abwehren.
Gut, ich überlege mir eine andere Variante. Den Selbstmord:
Nach so und so vielen Versuchen macht das Script via .htaccess den Laden dicht und deaktiviert sich selbst. Ich muss es dann explizit wieder starten.
Hmm. Gut dass ich keine Kunden habe.... ;)
Hallo Beat!
Den Selbstmord:
unlink $0;
??
Viele Grüße aus Frankfurt/Main,
Patrick
Moin Moin!
»» Kurz bevor Du Dir im Astrid-Lindgren-Gedenk-Webshop 10 Paar Pippi-Langstrumpf-Socken bestellst, rät Dir ein Freund, das sleep() mal auszukommentieren, schon fällt der Angriff in sich zusammen.
Also die Socken würden mich auf jeden Fall interessieren.
*g*
Ist es nicht so, dass du mit deiner Methode ja gar nicht darauf angewiesen bist, ob ich nun schlafe oder nicht?
Doch, Dein sleep() macht mir den Angriff wesentlich leichter. Wenn ich Dir mit falschem Input komme, blockiert Dein Prozess für 5 Sekunden einen Prozess bzw. Thread. Antwortest Du dagegen sofort, ist der Prozess wieder frei und ich muß mir wesentlich mehr Mühe geben, Deinen Server zu blockieren.
Aber ich gebe dir recht, insofern, dass ich dich zu einem billigen Angriff verleite.
Nun aber die Frage nach dem geeigneten Rezept. Du machst eine Wörterbuchattacke. Ich schlafe nicht. Irgendwo gibt es auf jeden Fall einen Flaschenhals (Stichwort Filelocking)
Wozu brauchst Du Filelocking bei einem Login? OK, wenn Du auf Krampf ein RDBMS vermeiden willst und stattdessen das Rad neu erfindest, wäre ein Lock hilfreich. Weder für SELECT ... FROM users WHERE name=? AND matchPassword(pwhash,?)=true noch für INSERT INTO sessions ... brauchst Du file locking. Und mit einer persistenten DB-Connection gibt es auch kein langsames, aufwendiges Connect für jeden Login-Versuch. Ganz im Gegenteil, die notwendigen SQL-Statements können gecacht werden und sind dann rattenschnell.
Die Frage ist also welche Art von Angriff will ich abwehren. Deinen Angriff mit Zombiebots kann ich nicht abwehren. Es ist dir ja schliesslich egal, was ich für einen Output sende.
Richtig, gegen Botnets ist kaum ein Kraut gewachsen. Da haben selbst richtig große Websites gelegentlich Probleme.
Was ich tun kann ist, abfragen gegen das Loggin Formular kontrollieren.
Nun logge ich. Ich logge IPs. Du sendest mir immer eine neue IP. Du hast so ziemlich viele Testmöglichkeiten, ohne dass ich mit dem Loggen irgenwo hin komme.
Indem ich allgemein unabhängig von der IP schlafe, verhindere ich das was ich kann: Angriffe gegen das Login Formular.
Andere Angriffsmöglichkeiten kann ich nicht abwehren.
Du kannst versuchen, mir den DoS so schwer wie möglich zu machen, in dem Du möglichst schnell entscheidest, dass ein Request durch einen Angriff und nicht durch einen schusseligen Benutzer zustande gekommen ist.
Gut, ich überlege mir eine andere Variante. Den Selbstmord:
Nach so und so vielen Versuchen macht das Script via .htaccess den Laden dicht und deaktiviert sich selbst. Ich muss es dann explizit wieder starten.
Juchu! 10.000 Requests und Dein Server ist dauerhaft tot, bis Du ihn explizit wieder reanimierst. Rate mal, wie ich Dich dann in Pippi-Langstrumpf-Socken bekomme:
# pseudo-perl, parallel auf ein paar Maschinen
while (!$beat->wearsLangstrumpfSocks()) {
if (post($login_url,{ name => random_string(), password => random_string() })!=HTTP_OK) {
# noch tot
sleep(30);
} else {
# bald tot
for (1..1e6) {
last if post($login_url,{ name => random_string(), password => random_string() })!=HTTP_OK; # schlage keinen toten Gaul ... ;-)
}
# sehr wahrscheinlich tot, spätestens nach ein paar Runden durch die while-Schleife
}
}
Das starte ich und warte ab, bis Dir der Kaffee oder die Geduld beim minütlichen Reanimieren des Servers ausgeht. Deine Kunden sehen währenddessen nahezu komplett in die Röhre, es sei denn, sie greifen während meines sleep(30) auf den frisch reanimierten Server zu.
Alexander
Hi,
Richtig, gegen Botnets ist kaum ein Kraut gewachsen. Da haben selbst richtig große Websites gelegentlich Probleme.
wenn ich das hier so lese, dann frage ich mich was bedeutet "gelegentlich Probleme"? Haben denn die Grossen überhaupt eine Chance sich zu wehren?
Ich nehme mal 2 Beispiele:
Google: Liege ich da richtig wenn ich vermute, die könnten total überlastete Server durch unzählige Angriffe/Requests mit unzähligen Umleitungen auf unzählige Reserveserver überstehen?
Dann gewinnt wohl am Ende der mit der grösseren Netzstruktur. Wobei ich mir da dann auch wieder nicht vorstellen kann, das dann Google gewinnt.
Anderes Beispiel Facebook oder Xing: Im Gegensatz zu Google erfordert die Webseite ein Login, was ein Abwehren bei solchen Attacken nicht so einfach mit beliebig vielen Mirror-Servern zu handeln wäre?
Nun mal ganz konkret gefragt: Kann eine grosse Webseite sich überhaupt schützen, wenn eine Profi-Gruppe es wirklich darauf anlegt die platt zu machen?
Falls nein, würde das bedeuten ein Internet-Zig-Millarden-Unternehmen wäre in Nullkommanix nichts mehr wert, wenn es drauf ankommt. Ein paar Tage offline oder fast nicht verfügbar und die Aktien würden ins Bodenlose fallen.
Peter
Moin Moin!
»» Richtig, gegen Botnets ist kaum ein Kraut gewachsen. Da haben selbst richtig große Websites gelegentlich Probleme.
wenn ich das hier so lese, dann frage ich mich was bedeutet "gelegentlich Probleme"? Haben denn die Grossen überhaupt eine Chance sich zu wehren?
Ja. Die meisten Angreifer sind nicht so gut, wie sie selbst glauben. Viele Angriffe sind maschinell erkennbar und können an Firewalls oder notfalls in der Anwendung geblockt werden. Das heißt nicht, dass die Firewall automatisch sieht, dass ein gewisses Paket ein Angriff ist. Aber ein fähiges Admin-Team kann der Firewall beibringen, dass Pakete mit einem gewissen Muster (z.B. ganz einfach $Request{'User-Agent'}=~/^lwp-simple/ && $Request{'Request-URI'}=~m|^/myapp/login.asp|) Angriffe sind und am besten gleich verworfen werden.
Ich nehme mal 2 Beispiele:
Google: Liege ich da richtig wenn ich vermute, die könnten total überlastete Server durch unzählige Angriffe/Requests mit unzähligen Umleitungen auf unzählige Reserveserver überstehen?
Google ist sicherlich ein besonderes Ziel, denn Googles Server-Landschaft ist extrem parallel und redundant, man könnte Google wahrscheinlich ein paar hundert Server zu Klump kloppen, ohne dass das Googles Service wesentlich beeinträchtigen würde. Server-Ausfälle sind bei Google an der Tagesordnung, schon aufgrund der nackten Server-Zahl.
Dann gewinnt wohl am Ende der mit der grösseren Netzstruktur. Wobei ich mir da dann auch wieder nicht vorstellen kann, das dann Google gewinnt.
Die Google-Leute haben sehr viel Mühe investiert, möglichst schnell zu antworten, egal was kommt.
DDoS auf Google halte ich nicht für unmöglich, aber für wesentlich schwerer als z.B. auf heise.de.
Anderes Beispiel Facebook oder Xing: Im Gegensatz zu Google erfordert die Webseite ein Login, was ein Abwehren bei solchen Attacken nicht so einfach mit beliebig vielen Mirror-Servern zu handeln wäre?
Da kommt es sehr darauf an, was angegriffen wird.
Wenn man bei einem Angriff zufällig noch genügend Infrastruktur übrig hat, kann man stumpf noch eine Hand voll weiterer Web-Server aufsetzen und zu den anderen "parallel schalten". Mit etwas Glück geht dem Angreifer dann irgendwann die Puste aus.
Typischerweise erreicht man bei solchen Plattformen unter www.example.com eben nicht einen einzelnen Webserver, sondern erstmal einen von mehreren Load Balancern, die eingehende Requests auf die eigentlichen Webserver hinter den Load Balancern verteilen, typischerweise anhand der Last auf den jeweiligen Webservern und anhand der Request-URL. Manchmal steht vor den Load Balancern auch noch eine Reihe Firewalls.
Damit ist es natürlich auch möglich, Angriffe in der Firewall zu blocken und den Rest im Load Balancer auf zusätzliche Server zu verteilen.
Nun mal ganz konkret gefragt: Kann eine grosse Webseite sich überhaupt schützen, wenn eine Profi-Gruppe es wirklich darauf anlegt die platt zu machen?
Nein. Wenn die Angreifer genügend Mittel und genügend Know-How haben, können sie de Website richtig Ärger machen. Ein oder mehrere Botnets wären für eine dermaßen gezielte Aktion natürlich sehr von Vorteil. Die Angriffe müßten sehr stark variieren und nahezu unfilterbar sein. Insider-Wissen über das Ziel wäre ebenfalls hilfreich, um die Schwachpunkte möglichst gezielt anzugreifen. Die üblichen Techniken dürften Bestechung oder Erpressung sein, oder vielleicht auch das Finden eines ausreichend frustrierten und rachsüchtigen Mitarbeiters. So ein Angriff wird aber kaum aus dem Hobby-Keller heraus passieren, das erfordert mehr Koordination und mehr Mittel.
Falls nein, würde das bedeuten ein Internet-Zig-Millarden-Unternehmen wäre in Nullkommanix nichts mehr wert, wenn es drauf ankommt. Ein paar Tage offline oder fast nicht verfügbar und die Aktien würden ins Bodenlose fallen.
Es wäre auf jeden Fall sehr schlecht für das Image, wenn die Website über Tage nicht erreichbar ist.
Alexander
Ist es nicht so, dass du mit deiner Methode ja gar nicht darauf angewiesen bist, ob ich nun schlafe oder nicht?
Doch, Dein sleep() macht mir den Angriff wesentlich leichter. Wenn ich Dir mit falschem Input komme, blockiert Dein Prozess für 5 Sekunden einen Prozess bzw. Thread. Antwortest Du dagegen sofort, ist der Prozess wieder frei und ich muß mir wesentlich mehr Mühe geben, Deinen Server zu blockieren.
na also , anderer Vorschlag:
Voraussetzung im Script: Ein Loginversuch ist nur auf der Basis einer existierenden sid-rid möglich.
Der Aufwand dazu ist in meiner Architektur eine Zeile Code.
Was bedingt das für deinen Angriff?
Damit du einen Angriff auf mein Script starten kannst, muss du dir zuerst eine sid-rid holen.
Das heisst an diesem Punkt darfst du den Output nicht mehr vernachlässigen:
Fakt: sid-rid ist eine One-Time ID.
Aber ich gebe dir recht, insofern, dass ich dich zu einem billigen Angriff verleite.
Nun aber die Frage nach dem geeigneten Rezept. Du machst eine Wörterbuchattacke. Ich schlafe nicht. Irgendwo gibt es auf jeden Fall einen Flaschenhals (Stichwort Filelocking)Wozu brauchst Du Filelocking bei einem Login? OK, wenn Du auf Krampf ein RDBMS vermeiden willst und stattdessen das Rad neu erfindest, wäre ein Lock hilfreich. Weder für SELECT ... FROM users WHERE name=? AND matchPassword(pwhash,?)=true noch für INSERT INTO sessions ... brauchst Du file locking. Und mit einer persistenten DB-Connection gibt es auch kein langsames, aufwendiges Connect für jeden Login-Versuch. Ganz im Gegenteil, die notwendigen SQL-Statements können gecacht werden und sind dann rattenschnell.
Den kurz abgehandelt: No SQL... no PHP ;)
Was ich tun kann ist, abfragen gegen das Loggin Formular kontrollieren.
Nun logge ich. Ich logge IPs. Du sendest mir immer eine neue IP. Du hast so ziemlich viele Testmöglichkeiten, ohne dass ich mit dem Loggen irgenwo hin komme.
Indem ich allgemein unabhängig von der IP schlafe, verhindere ich das was ich kann: Angriffe gegen das Login Formular.
Andere Angriffsmöglichkeiten kann ich nicht abwehren.Du kannst versuchen, mir den DoS so schwer wie möglich zu machen, in dem Du möglichst schnell entscheidest, dass ein Request durch einen Angriff und nicht durch einen schusseligen Benutzer zustande gekommen ist.
Diese Analyse bedingt das Loggen und analysieren mehrerer Requests.
Das kann sich reduzieren, wenn es nur bei Login oder anderen Authentifizierungs-Aufgaben betreiben wird.
Die Frage ist nur, welche Information verwerte ich? Wenn ich zum Schluss komme, dass der Angriff sich nicht auf IPs einschränken lässt, dann sind wir wieder am gleichen Punkt.
OK Meistens ist die zahl der IPs irgendwo schon beschränkt und ich habe da auch mal einen Logger geschrieben, welcher IP/16 und IP/24 Bereiche in eine Queue schiebt und andere wieder befreit. Aber auc damit machst du mir den laden dicht.
Wenn ich diese Queue regelmässig lösche, ist das auch das selbe wie dein folgendes Szenario.
Gut, ich überlege mir eine andere Variante. Den Selbstmord:
Nach so und so vielen Versuchen macht das Script via .htaccess den Laden dicht und deaktiviert sich selbst. Ich muss es dann explizit wieder starten.Juchu! 10.000 Requests und Dein Server ist dauerhaft tot, bis Du ihn explizit wieder reanimierst. Rate mal, wie ich Dich dann in Pippi-Langstrumpf-Socken bekomme:
Wir haben uns noch nicht darüber unterhalten wann und wie ich den Laden dicht mache, bis zu deinem sleep(3)
pseudo-perl, parallel auf ein paar Maschinen
while (!$beat->wearsLangstrumpfSocks()) {
if (post($login_url,{ name => random_string(), password => random_string() })!=HTTP_OK) {
Willst du mir jetzt Socken andrehen, oder pws hacken?
Nach obiger Ergänzung wird deine Aufgabe etwas schwieriger.
Setze einen normalen Request ab, Lese die sid-rid aus dem Content aus und sende sie zusammen mit den erforderlichen Feldern.
dein !=HTTP_OK könnte ich ganz schön narren.
# noch tot
sleep(30);
Danke, danke, 30 Sekunden Lebensfrist... im besten Fall.
} else {
# bald tot
for (1..1e6) {
last if post($login_url,{ name => random_string(), password => random_string() })!=HTTP_OK; # schlage keinen toten Gaul ... ;-)
Warum denn nicht? Ich habe schon genug, die es versuchen.
Ein script dass so viele Requests absetzt ist ziemlich auffällig, auch wenn du es auf das absolut notwendigste zu reduzieren vermagst.
Gut, du kannst das von deinem Badewannenserver aus machen. Hoffentlich badest du schnell.
Nehmen wir das revidierte Szenario, wonach du zuerst die sid-rid erhalten musst. Damit muss bei dir ein einzelner Prozess länger am Leben sein als mein Scriptzyklus. Willst du deinen Angriff von einem einzigen Server aus starten.
Das eröffnet dann die Frage, wer wird eigentlich gebremmst?
}
# sehr wahrscheinlich tot, spätestens nach ein paar Runden durch die while-Schleife
}
}
>
> Das starte ich und warte ab, bis Dir der Kaffee oder die Geduld beim minütlichen Reanimieren des Servers ausgeht. Deine Kunden sehen währenddessen nahezu komplett in die Röhre, es sei denn, sie greifen während meines sleep(30) auf den frisch reanimierten Server zu.
Ok ich erspare dir den Rewrite nach der obigen Ergänzung. Er wird nicht sonderlich schwer sein. Du wirst dich aber den typischen Bot-Netz Strategien nähern müssen. Ich zweifle nicht dass kleiner Botnetze auch mal kostenlos zu haben sind. Grössere hingegen werden dich dann etwas kosten.
mfg Beat
--
><o(((°> ><o(((°>
<°)))o>< ><o(((°>o
Moin Moin!
na also , anderer Vorschlag:
Voraussetzung im Script: Ein Loginversuch ist nur auf der Basis einer existierenden sid-rid möglich.
Fakt: sid-rid ist eine One-Time ID.
Kann ich Deinen ID-Generator überlasten? Dann wäre der mein Angriffsziel.
Wie viel Arbeit macht es Dir, die ID zu prüfen? Wenn dich das zu lange beschäftigt, verstopfe ich Deinen Server mit falschen IDs.
Kann ich die ID selbst mit ausreichender Wahrscheinlichkeit vorhersagen? Dann brauche ich mich um die ID nicht weiter zu kümmern, sondern berechne sie selbst.
»» Du kannst versuchen, mir den DoS so schwer wie möglich zu machen, in dem Du möglichst schnell entscheidest, dass ein Request durch einen Angriff und nicht durch einen schusseligen Benutzer zustande gekommen ist.
Diese Analyse bedingt das Loggen und analysieren mehrerer Requests.
Nö, nicht unbedingt. Eingabe-Validierung hilft auch schon:
Request ohne ID, mit zu kurzer oder zu langer ID, mit zu kurzem oder zu langem Benutzernamen oder Passwort, mit syntaktisch falschem Benutzernamen (E-Mail-Adresse als Benutzername) kannst Du stumpf abwürgen, ohne die Benutzer-DB anfassen zu müssen.
»» > Gut, ich überlege mir eine andere Variante. Den Selbstmord:
»» > Nach so und so vielen Versuchen macht das Script via .htaccess den Laden dicht und deaktiviert sich selbst. Ich muss es dann explizit wieder starten.
»»
»» Juchu! 10.000 Requests und Dein Server ist dauerhaft tot, bis Du ihn explizit wieder reanimierst. Rate mal, wie ich Dich dann in Pippi-Langstrumpf-Socken bekomme:Wir haben uns noch nicht darüber unterhalten wann und wie ich den Laden dicht mache,
Naja, ob Deine Anwendung bei 10.000 oder 1 Mio. böser Requests in die Klinge springt, ist relativ egal.
bis zu deinem sleep(3)
»» [code lang=perl]
»» # pseudo-perl, parallel auf ein paar Maschinen
»» while (!$beat->wearsLangstrumpfSocks()) {
»» if (post($login_url,{ name => random_string(), password => random_string() })!=HTTP_OK) {Willst du mir jetzt Socken andrehen, oder pws hacken?
Rate mal! ;-)
Nach obiger Ergänzung wird deine Aufgabe etwas schwieriger.
Setze einen normalen Request ab, Lese die sid-rid aus dem Content aus und sende sie zusammen mit den erforderlichen Feldern.
Kann ich komplett in meiner (modifizierten) post()-Routine erledigen. Oder ich rate die sid-rid gut genug, um mir das Abholen zu sparen.
dein !=HTTP_OK könnte ich ganz schön narren.
Ja, das ist eine Schwachstelle dieses kleinen Nervensäge-Scripts. post() müßte Header und Body der Response selbst prüfen und "tot", "falsches Passwort", "richtiges Passwort", "neuer Trick von Beat" zurückliefern.
»» # noch tot
»» sleep(30);Danke, danke, 30 Sekunden Lebensfrist... im besten Fall.
Ich muß meine Rechner ja nicht unnötig belasten. ;-) Es brint ja nichts, stundenlang auf Deinen Server einzuprügeln, wenn der längst tot ist. In der Zeit kann ich ja besser jemand anderem Socken "nahelegen".
»» } else {
»» # bald tot
»» for (1..1e6) {
»» last if post($login_url,{ name => random_string(), password => random_string() })!=HTTP_OK; # schlage keinen toten Gaul ... ;-)Warum denn nicht? Ich habe schon genug, die es versuchen.
Wie gesagt, ich kann mein Botnet für andere Ziele benutzen, oder ich lasse mein Botnet etwas ruhen, damit die Zombie-PCs nicht so extrem ausgebremst werden.
Ein script dass so viele Requests absetzt ist ziemlich auffällig, auch wenn du es auf das absolut notwendigste zu reduzieren vermagst.
Richtig. Ich behaupte ja auch gar nicht, dass das perfekt ist. Ganz im Gegenteil, es ist eher stümperhaft. Ich hab ja auch nicht sonderlich viel Energie reingesteckt. Verteile ich die for-Schleife auf 10.000 Zombies, macht jeder nur noch 100 Requests. Verteilt über ein oder zwei Minuten fallen die pro Zombie gar nicht mehr auf.
Gut, du kannst das von deinem Badewannenserver aus machen. Hoffentlich badest du schnell.
Nehmen wir das revidierte Szenario, wonach du zuerst die sid-rid erhalten musst.
Muß ich das? Es reicht aus, wenn ich die ID gut raten kann. Wenn ich in 50% aller Fälle richtig liege, kannst Du die Hälfte meiner Requests sofort wegwerfen, aber den Rest mußt Du immer noch intensiv testen.
Damit muss bei dir ein einzelner Prozess länger am Leben sein als mein Scriptzyklus.
Nö, warum? Jeder einzelne Prozess besorgt sich die ID oder rät sie und macht dann einen POST-Request.
Ein etwas gemeines Gegenmittel wäre, die ID durch client-seitiges Javascript berechnen zu lassen, und zwar so, dass ich eine möglichst vollständige Javascript-Engine samt Browser-Simulation brauche. Das bringt so erstmal wenig, kostet mich nur ein paar CPU-Zyklen mehr.
Dann kannst Du aber Deinerseits versuchen, meine JS-Engine + Browser-Simulation zu erkennen (z.B. an Fehlern in der Implementation) und in Javascript möglichst viel Rechenzeit zu verbrennen.
Die üblichen Nachteile sind natürlich offensichtlich: Ohne JS keine Anmeldung, und allzu perverses Javascript (gegen meine Rechenleistung) kann auch harmlose Browser verwirren oder sabotieren.
Wahrscheinlich würde ich dagegen das automatische ID-Raten einsetzen, damit Du mir eben keine Rechenzeit klauen kannst.
Willst du deinen Angriff von einem einzigen Server aus starten.
Nö, ist ja auch gar nicht nötig. Ich muß nur mein Botnet kontrollieren. Die Mißerfolge der Zombies interessieren mich nicht, als Antwort will ich nur eine Liste der gefundenen Accounts und/oder den Hinweis "Server tot" haben.
Das eröffnet dann die Frage, wer wird eigentlich gebremmst?
Du. Ich kann im Botnet massiv parallel arbeiten. Wenn der Job zu groß wird, teile ich den Job auf und lege ich ein paar Tausend Zombies nach.
»» Das starte ich und warte ab, bis Dir der Kaffee oder die Geduld beim minütlichen Reanimieren des Servers ausgeht. Deine Kunden sehen währenddessen nahezu komplett in die Röhre, es sei denn, sie greifen während meines sleep(30) auf den frisch reanimierten Server zu.
Ok ich erspare dir den Rewrite nach der obigen Ergänzung. Er wird nicht sonderlich schwer sein. Du wirst dich aber den typischen Bot-Netz Strategien nähern müssen. Ich zweifle nicht dass kleiner Botnetze auch mal kostenlos zu haben sind. Grössere hingegen werden dich dann etwas kosten.
Richtig. Das Botnet finanziere ich über die verkauften Socken! ;-)
Alexander
Hallo Alexander,
dein Szenanrio beschreibt das was ich mich schon immer gefragt habe.
Mit diesen Methoden müsste dich jeder Service zum Erliegen kommen, egal wer? Das jetzt Müller-Meier mit seiner kleinen Webseite dem nicht ausgesetzt wird, liegt wohl eher an dem Desinteresse des Angreifers.
Aber wie sieht das mit unseeins aus, die wir ja mehr oder weniger von Fach sind, welche Möglichkeiten haben wir um uns gegen sowas zu wehren?
Dein kompletts Szenario erschien hier schon öfter aber nie so detailliert, sow aren hier schon Fragen dazu wie man unerwünschte HTTP-Anfragen begrenzen kann oder Speed-Grenzen setzt, aber Lösungen waren nicht wirklich vorhanden oder wenn dann nur teilweise mit extemen Servereingriffen, wobei ja nicht jeder Kunde einen eigene dedizierten Server hat.
Wie auch immer ich fande das sehe lesenwert(vor allem visuell, nicht fachchinesisch) und fände schön wenn daraus ein SelfhtmlArtikel werden würde.
Gruss
Peter
Moin Moin!
dein Szenanrio beschreibt das was ich mich schon immer gefragt habe.
Wie man Leute dazu bringt, mit zwei verschiedenen Socken durhc die Gegend zu laufen? ;-)
Mit diesen Methoden müsste dich jeder Service zum Erliegen kommen, egal wer?
Ja. Gegen DDoS auf wenige Server ist kaum ein Kraut gewachsen, das haben auch schon "die Großen" mehrfach feststellen müssen. Wenn der Service allerdings auch auf sehr viele Maschinen in sehr vielen Netzen verteilt ist, ist DDoS wesentlich schwieriger. In dem Fall greift man besser die koordinierende Infrastruktur an.
Das jetzt Müller-Meier mit seiner kleinen Webseite dem nicht ausgesetzt wird, liegt wohl eher an dem Desinteresse des Angreifers.
Richtig. Wenig Motivation und wenig Bereitschaft, Geld oder Mühe in den Angriff zu investieren. Mit genügend "krimineller Energie" sucht man sich ein gutes Ziel, fährt eine kurze DDoS-Welle, und teilt dem Opfer mit, dass man sowas in Zukunft unterläßt, sofern das Opfer sich finanziell ausreichend erkenntlich zeigt, einen ungeliebten Dienst einstellt oder einen eingestelltne Dienst wieder aktiviert.
Aber wie sieht das mit unseeins aus, die wir ja mehr oder weniger von Fach sind, welche Möglichkeiten haben wir um uns gegen sowas zu wehren?
Nachdenken, nachdenken, nachdenken. Ganz schwer ist der Rollenwechsel vom Entwickler zum Angreifer, weil man sein mühsam aufgezogenes Kind plötzlich mit aller Gewalt verprügeln und mißbrauchen soll.
Im Prinzip macht man aber genau dass, wass ich mit Beat durchgespielt habe. Man denkt sich einen ausreichend motivierten und völlig skrupellosen Angreifer aus, der auf beliebig viele Resourcen zurückgreifen kann, und läßt den das eigene Produkt angreifen.
Ein Kollege, der den Angreifer spielt, kann sehr hilfreich sein.
Naürlich sollte man auch so ungefähr wissen, wie Angriffe funktionieren. Es gibt genügend Leute, die Angriffe sehr ausführlich dokumentiert haben. Es muß ja nicht immer DDoS sein, es gibt wesentlich feinere Werkzeuge.
Dein kompletts Szenario erschien hier schon öfter aber nie so detailliert, sow aren hier schon Fragen dazu wie man unerwünschte HTTP-Anfragen begrenzen kann oder Speed-Grenzen setzt, aber Lösungen waren nicht wirklich vorhanden oder wenn dann nur teilweise mit extemen Servereingriffen, wobei ja nicht jeder Kunde einen eigene dedizierten Server hat.
Wenn Du "nur" ein Hosting-Paket hast, wird der Provider schonmal ein Auge auf die Datenmenge haben, und notfalls Deine Site mal kurz abklemmen. Perfektes DDoS, aber eben nur auf Deine Site, der Rest der Kunden hat Ruhe.
Eine absolute Lösung gegen DDoS gibt es nicht, auch das Drosseln von HTTP-Requests hilft eben nicht gegen DDoS, es verstärkt den Effekt nur noch.
Du kannst eigentlich nur hoffen, dass der Angreifer nicht so gut ist, wie er glaubt. Wenn er z.B. beim Gedankenspiel-Angriff auf Beat blöd genug ist, den User-Agent-Header auf "libwww-perl/x.yyy" zu lassen, ist der Angriff schon in der Firewall vor dem Server abwürgbar, notfalls durch eine Apache-Regel, die für alle Requests mit dem User-Agent stumpf 404 liefert. PHP (oder worauf auch immer die Anwendung basiert) sieht den Request gar nicht.
Wie auch immer ich fande das sehe lesenwert(vor allem visuell, nicht fachchinesisch) und fände schön wenn daraus ein SelfhtmlArtikel werden würde.
Danke für das Lob, aber zu so einem Artikel gehört doch wesentlich mehr Arbeit als nur ein Posting. Hier hab ich nur Beats Idee zerlegt, sleep() wäre eine gute Idee gegen gescriptete Angriffe. Für einen Artikel ist das viel zu speziell. Über das Absichern von Websites kann man Bücher schreiben, und es wurden auch schon reichlich viele geschrieben, darunter sicherlich auch ein paar gute.
Alexander
Hallo,
Ich habe mal versucht mit Ajax ein Login Script zu erstellen. Das ist mir mir meiner Meinung nach auch einigermassen gut gelungen.
leider ist dies nicht der Fall.
Ist mein Script so sinnvoll,
Nein, der Einsatz von Ajax ist hier völlig überflüssig.
sicher etc..
Noch unsicherer geht's ja fast nicht mehr. Man benötigt noch nicht mal einen gültigen Benutzernamen, um sich einzuloggen :-)
Ein paar werden sich vieleicht Fragen warum Ajax... Ich wollte einen Login der auch schön ausschaut und mit Ajax lassen sich Ladegrafiken etc meiner Meinung nach am besten verwirklichen.
und wo gibt es hier Ladegrafiken? Da Du bei Erfolg weiterleitest (prüfst Du dort die erfolgreiche Anmeldung?), ist Ajax - wie ich schon anmerkte - überflüssig.
[code lang=php]
<?php
session_start();if(isset($_POST['name']))
{
if(isset($_POST['ajax']))
{
$pw = md5($_POST['pw']);
$name = $_POST['name'];$con = mysql_connect("localhost","Benutzername","Passwort");
mysql_select_db("Datenbank",$con);
$sql="SELECT userid FROM user WHERE username='".$name."' AND passwort='".$pw."' LIMIT 1";
Du bist anfällig für SQL-Injection, weil Du Benutzereingaben nicht kontextgerecht behandelst. Durch die überflüssige LIMIT-Klausel machst Du es dem Angreifer doppelt leicht. Man benötigt daher weder Benutzernamen noch Passwort, um sich anmelden zu können.
$result= mysql_query($sql);
Keine Überprüfung, ob mysql_query vielleicht fehlschlägt. Nett.
if(mysql_num_rows($result) == 1)
Verflixt. Wenn nicht 0 Datensätze herauskommen, wird genau einer herauskommen. Mit einem geschickt gewählten Benutzernamen kommt immer genau ein Datensatz heraus.
{
$user=mysql_fetch_assoc($result);
$userid = $user['userid'];
$sql="UPDATE user SET session='".session_id()."' WHERE userid=".$userid;
[...]
elseif(!isset($_POST['ajax']))
{
$pw = md5($_POST['password']);
$name = $_POST['username'];
Du wiederholst eine Menge Code, ein Zeichen für Verbesserungspotential.
$con = mysql_connect("localhost","Benutzername","Passwort");
mysql_select_db("Datenbank",$con);
$sql="SELECT userid FROM user WHERE username='".$name."' AND passwort='".$pw."' LIMIT 1";
$result= mysql_query($sql);
Gleiches wie oben.
[...]
mysql_query($sql);
Header("Location: home.php");
häufig gemachter Fehler beim Location-Header. Dieser benötigt eine absolute URI. Was ist wenn jemand seine Anfrage gleich an home.php schickt? Du musst in jeder Seite, die nur über das Login erreichbar sein soll, die erfolgreiche Anmeldung überprüfen.
Freundliche Grüße
Vinzenz
Hallo,
» sicher etc..
Noch unsicherer geht's ja fast nicht mehr. Man benötigt noch nicht mal einen gültigen Benutzernamen, um sich einzuloggen :-)
nur als Anmerkung: Ein Beispiel wäre folgender Benutzername:
irgendwer' OR 1 OR '1
mit beliebigem Passwort. Erfolgreich getestet :-) [1]
Freundliche Grüße
Vinzenz
[1] Setzt deaktivierte Magic Quotes voraus. Dem Handbuch kann man
entnehmen, warum es gut ist, diese zu deaktivieren.
Hallo,
Vielen Dank, du hast mir ziemlich die Augen geöffnet.
nur als Anmerkung: Ein Beispiel wäre folgender Benutzername:
irgendwer' OR 1 OR '1
mit beliebigem Passwort. Erfolgreich getestet :-)
Hast du einen Tipp für mich wie ich das verbessern könnte?
Liebe Grüsse
Thomas
Hallo,
Vielen Dank, du hast mir ziemlich die Augen geöffnet.
» nur als Anmerkung: Ein Beispiel wäre folgender Benutzername:
»
» irgendwer' OR 1 OR '1
»
» mit beliebigem Passwort. Erfolgreich getestet :-)Hast du einen Tipp für mich wie ich das verbessern könnte?
im ersten Schritt solltest Du die SQL-Injection verhindern. Behandle daher Deine Variablen mit mysql_real_escape_string(). Beachte die Magic Quotes, die ich Dir bereits verlinkt habe. Solltest Du diese nicht serverseitig deaktivieren können, mache ihre Auswirkungen rückgängig, wie es in Beispiel 2 steht. Die LIMIT-Klausel kannst Du dennoch entsorgen. Sie bringt keinerlei Nutzen, kann jedoch (wie demonstriert) Schaden anrichten.
Der Artikel Sessionbassiertes Loginsystem in SELFHTML aktuell, zeigt Dir, mit welch' geringem Aufwand Du jede geschützte Seite so aufbereiten kann, dass ein unbefugter Zugriff nicht möglich ist (Überprüfung der Anmeldung auf *jeder* Seite).
Wenn von Deiner Login-Seite nach erfolgreichem Einloggen eine Weiterleitung erfolgt, welchen Nutzen versprichst Du Dir vom Ajax-Einsatz. Es wird eh' eine neue Seite geladen, somit tut es ein ganz normales Formular. Ajax-Einsatz nur um Ajax willen halte ich nicht für sinnvoll.
Freundliche Grüße
Vinzenz
Moin Moin!
Ich wollte einen Login der auch schön ausschaut und mit Ajax lassen sich Ladegrafiken etc meiner Meinung nach am besten verwirklichen.
Wozu? Der Browser zeigt in aller Regel deutlich an, dass eine neue Seite geladen wird, es sei denn, Du fängst an, mit AJAX herumzupfuschen. Die Ladegrafik muß auch erstmal geladen werden, das dauert eine Weile und kostet unnütz Resourcen des Servers, der Netzwerkverbindung und des Clients.
Und nein, nicht jeder hat eine Internet-Anbindung, deren Bandbreite sich in zwei- oder dreistelligen MBit/s bemißt. Es gibt auch 2009 noch genügend Leute, für die "schnelles Internet" ein CONNECT 33600 ihres V.90-Modems ist. Oh, und aus aktuellem Anlaß: Es gibt Internet-Anbindungen mit Latenzzeiten im Sekundenbereich. Klick -> 36.000 km hoch zum Satellit -> 36.000 km runter vom Satellit -> Internet (diverse Router) -> 36.000 km hoch zum Satellit -> 36.000 km runter vom Satellit -> Datenverarbeitung -> Reaktion auf dem Schirm. Das ist "richtig schnelles Internet" für Leute, die das V.90-Modem unter den nächsten Trecker geschmissen haben. Mitten in Deutschland, nicht in der Antarktis, wohlgemerkt. DSL ist NICHT flächendeckend verfügbar, genauso wenig wie GSM, GPRS oder UMTS.
Alexander
Hallo
Und nein, nicht jeder hat eine Internet-Anbindung, deren Bandbreite sich in zwei- oder dreistelligen MBit/s bemißt. Es gibt auch 2009 noch genügend Leute, für die "schnelles Internet" ein CONNECT 33600 ihres V.90-Modems ist.
Jaja, *das* waren Zeiten (bei mir bis vor nichtmal einem Jahr). Mit 'nem 33.6-er Modem mit günstigstenfalls 1.irgendwas bis 3.6 kB/s. Für reine Textseiten oder mit entsprechend optimierten Grafiken gespickte Seiten war das auch durchaus ausreichend. Aber jeder Download mit mehr als einigen wenigen (0.x bis etwa 3) Megabyte war schon rein finanziell nicht möglich, vom damit verbundenen Zeitaufwand (diverser Stunden) wollen wir garnicht erst sprechen.
An dieser Stelle ein "Hoch" auf USB-Speichersticks und Leute, die schon DSL hatten! :-)
Tschö, Auge