0

ユーザーをログインさせ、ページでのログインを検証するシステムのアイデアがあります。
そこにはたくさんのシステムがあることを認識していますが、主に自分のアイデアが何か良いものであるかどうかに興味がありました. 私はいくつかの調査を行いましたが、ほとんどの結果は、私が常に重要なプラクティスであると考えていたもの (パスワードの暗号化など) を除外しているようです。おそらくより安全な既製のソリューションを探すのは難しいでしょうが、アプリケーションのセキュリティを実際に扱ったことがなく、フィードバックを得たいと思っていました.

ユーザーがログインすると、名前とパスワードがデータベースに対して検証され、パスワードは SHA256 とランダムに生成されたソルトを使用して暗号化され、全体の文字列 (ソルトと暗号化されたパスワードの両方が 128 文字の長さ) になります。パスワード検証コードは次のとおりです。

 function ValidatePassword($password, $correctHash)
 {
    $salt = substr($correctHash, 0, 64); //get the salt from the front of the hash
    $validHash = substr($correctHash, 64, 64); //the SHA256

    $testHash = hash("sha256", $salt . $password); //hash the password being tested
    //if the hashes are exactly the same, the password is valid
    return $testHash === $validHash;
}

ログインが有効な場合、トークンが割り当てられます。このトークンはパスワード暗号化に似ていますが、暗号化されたエポックと別のランダム ソルトを格納します。トークン、ログイン時刻、有効期限、ユーザー名をDBに格納し、ユーザー名とトークンをセッション情報として送信する。

トークンを作成するコードは次のとおりです。

function loginUser($email)
{
  $thetime = time();
  $ip = $_SERVER['REMOTE_ADDR'];

  $dbuser="///";
  $dbpass="///";
  $dbtable="tokens";
  mysql_connect(localhost,$dbuser,$dbpass);
  mysql_select_db("///") or die( "Unable to select database");

  //Generate a salt
  $salt = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM));
  //Hash the salt and the current time to get a random token
  $hash = hash("sha256", $salt . $password);
  //Prepend the salt to the hash
  $final = $salt . $hash;

  $exptime = $thetime + 3600;

  //Store this value into the db
  $query = "INSERT INTO `spanel`.`tokens` VALUES ('$final', $thetime, $exptime,    $thetime, '$ip', MD5('$email') )";
  mysql_query($query) or die ("Could not create token.");

  //Store the data into session vars
  $_SESSION['spanel_email'] = $email;
  $_SESSION['spanel_token'] = $final;

  return true;

}

ページに到達すると、持っているトークンとユーザー名が DB に対してチェックされます。チェックに問題がなければ、有効期限が更新され、ページが読み込まれます。そのコードは次のとおりです。

function validateUser($page)
{
  //Grab some vars
  $thetime = time();
  $ip = $_SERVER['REMOTE_ADDR'];
  $token = $_SESSION['spanel_token'];
  $email = $_SESSION['spanel_email'];

  $dbuser="///";
  $dbpass="///";
  $dbtable="tokens";
  mysql_connect(localhost,$dbuser,$dbpass);
  mysql_select_db("///") or die( "Unable to select database");

  //Global var
  //Get the var for token expire
  $token_expire = 3600;
  //Validate the token
  $query = "SELECT * FROM `tokens` WHERE `token` LIKE '$token' AND `user_id` LIKE   MD5('$email') AND `exp` > $thetime";
  $result = mysql_query($query) or die(mysql_error());
  //Check if we have a valid result
  if ( mysql_num_rows($result) != 1 ) {
    //Logout the user
    //Destroy the session
    session_destroy();
    //Redirect
    header("location: /spanel/login.php?denied=1");
    exit();
    //(Since the token is already invalid, there's no reason to reset it as invalid)
  }
  $row = mysql_fetch_assoc($result);

  //Update the token with our lastseen
  $newexp = $thetime + $token_expire;
  $query = "UPDATE `spanel`.`tokens` SET `exp` = $newexp, `lastseen_ip` = $thetime,    `lastseen_ip` = '$ip' WHERE `token` LIKE '$token'";
  mysql_query($query);

}

フィードバック (良くも悪くも) は大歓迎です。私が言ったように、私はあまりセキュリティを行っていないので、ポインタを取得したいと思っていました.

編集:ログインシステムを効果的に作成する能力を過大評価しているのではないかと心配しています. そうは言っても、このおそらく欠陥のあるアイデアであるごちゃごちゃした混乱を理解しようとするのをやめようと決心したかどうかは理解できます。

それでも、ログインページのphpコードは次のとおりです。(ここで言われたことの後、パスワードを POST するだけでは大したことではないことがわかりました)。

    $email = $_POST['email'];
    $password = $_POST['password'];
    $dbuser="///";
    $dbpass="///";
    $dbtable="///";
    mysql_connect(localhost,$dbuser,$dbpass);
    mysql_select_db("spanel") or die( "Unable to select database");
    $query = "SELECT * FROM users WHERE `email` LIKE '$email'";
    $result=mysql_query($query) or die(mysql_error());
    $num=mysql_num_rows($result);
    $row = mysql_fetch_array($result);
    if ( ValidatePassword($password, $row['hash']) == true ) {
      loginUser($email);
      header("location: /spanel/index.php");
    } else {
      echo "<p>Login Failed.</p>";
    }

これは、アカウントの作成時にパスワードのソルトとハッシュを生成するビットです。

 function HashPassword($password)
 {
    $salt = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM)); //get 256 random bits in hex
    $hash = hash("sha256", $salt . $password); //prepend the salt, then hash
    //store the salt and hash in the same string, so only 1 DB column is needed
    $final = $salt . $hash; 
    return $final;
}

フィードバックをお寄せいただきありがとうございます。私の知識不足による問題が、攻撃の後ではなく、ここで見つかってよかったです。

4

3 に答える 3

1

1 つには、そのようなハッシュは安全ではありません。sha256 は、少なくとも短いパスワードの場合、簡単に破ることができます。ハッシュ ストレッチを使用する必要があります。いくつかの PBKDF2 実装を見つけるか、sha256での「for ループ」に関するウィキペディアの提案を使用できるかどうかを確認してください。さらに、セッション変数を増やしても何を達成できるかわかりません。validateuser() の機能がわかりません。まだセッション ID に依存しているか、何か不足しています。

于 2012-05-14T17:08:25.893 に答える
1

sivannと同様に、追加のspanel_tokenの理由もわかりません。効果的に行われているように見えるのは、トークンの有効期限が切れた後にセッションが無効になることを確認することだけです。条件のtokenuser_idの両方の値WHEREがセッションに保存され、ログイン中にのみ設定されるため、変更されません。ただし、セッションの有効期限ははるかに簡単に実装できます。


しかし、それとは別に、さらに重要なことは、コードが SQL インジェクションに対して脆弱であることです。あなたがここに投稿した知識があれば簡単です。必要なのは、次の手順を実行することだけです。

  • emailに注入され たユーザーの列の数を調べます。UNION SELECT

    ' UNION SELECT null, …, null WHERE ''='
    

    間違った数の列が入力された場合、スクリプトは MySQL エラーをスローします。それ以外の場合は、「ログインに失敗しました」。現れる。ありがとうございます。

  • 次のクエリを使用します。

    SELECT t1.* FROM users t1 RIGHT JOIN (SELECT email, '000000000000000000000000000000000000000000000000000000000000000060e05bd1b195af2f94112fa7197a5c88289058840ce7c6df9693756bc6250f55' hash FROM users LIMIT 1) t2 USING (email);
    

    元のハッシュ列の値ではなく、値000000000000000000000000000000000000000000000000000000000000000060e05bd1b195af2f94112fa7197a5c88289058840ce7c6df9693756bc6250f55が各レコードに挿入されます。先頭の s はソルトで、残りの文字列は空のパスワード文字列のソルト化された SHA-256 ハッシュ値であり、有効なパスワードになります。0

    そのため、パスワードフィールドに空の文字列を入力し、電子メールフィールドに次のように入力することになります。

    ' UNION SELECT t2.* FROM users t1 RIGHT JOIN (SELECT email, '000000000000000000000000000000000000000000000000000000000000000060e05bd1b195af2f94112fa7197a5c88289058840ce7c6df9693756bc6250f55' hash FROM users LIMIT 1) t2 USING (email) WHERE ''='
    

これは、任意のユーザーとして「認証」を受けるのに十分なはずです。

于 2012-05-15T18:53:56.963 に答える
-1

ソルト/ハッシュシステムについてコメントするだけです:データベースにパスワードと一緒にソルトを保存すると、ソルトの目的が無効になります-データベースが危険にさらされている場合、ソルトはセキュリティの観点から役に立たなくなります。セキュリティを破る。ソルトの目的は、ハッシュする値に適切な長さの秘密の文字列を追加することにより、ハッシュされた単語を推測するのにかかる時間を増やすことです。

于 2012-05-14T17:15:11.633 に答える