1

私はSQLに不慣れで、phpでログインフォームを作成しようとしています。ブルートフォース攻撃を防ぐために、ログインフォームに少しIPブロックを実行させたいです。したがって、usersとloginattemptsの2つのテーブルがあります。ユーザー名とパスワードの組み合わせが正しい場合にユーザーの名前/IDを返す選択を実行しようとしていますが、その正確性に関係なく、ログイン試行クエリの結果が必要です。ここに少しのコードがあります。

まず、次のようにして、loginattemptテーブルにエントリがあることを確認します。

INSERT INTO loginattempts (ip) VALUES(:ip)
            ON DUPLICATE KEY UPDATE attempt=attempt+1

次に、次のような選択を行います。

SELECT users.username, users.id, loginattempts.attempt
             FROM users, loginattempts
             WHERE users.username = :username
             AND users.password = :password
             AND loginattempts.ip = :ip

ただし、いずれかの条件が満たされない場合、これは明らかに機能しません。単一のクエリでこれをどのように達成できますか?

4

1 に答える 1

2

テーブルは関連していないため、これはおそらく、ログイン試行を取得するための副選択で最も簡単に実行できます。

SELECT
  users.username,
  users.id,
  /* COALESCE() to return 0 if no attempt yet logged */
  COALESCE((SELECT attempt FROM loginattempts WHERE ip = :ip),0) AS attempt
FROM uusers
WHERE 
  username = :username
  AND password = :password

トリッキーなデカルト結合を実行して試行をプルすることは可能ですが、ユーザーとIPの両方に対して個別の行を探しているため、これはおそらく十分に高速です。にインデックスがあることを確認してくださいloginattempts.ip

アップデート

何らかの状況で列を取り戻す必要がある場合は、前述のトリッキーな左結合を使用できます。ONIPによって返される行は1つだけなので、デカルト結合(句なし)で逃げることができます。

SELECT
  username,
  userid,
  attempt
FROM
  /* Should always return exactly one row */
  (SELECT COALESCE((SELECT attempt FROM loginattempts WHERE ip = :ip),0) AS attempt)
  /* left joins against users with no ON condition, so if user doesn't match NULLs will return */
  LEFT JOIN users
WHERE 
  username = :username
  AND password = :password
于 2012-08-25T11:31:38.630 に答える