1

私は PHP で一種の IP ブラックリストを実装しようとしてきました。ここでは、次のスキーマを使用して、失敗したログイン試行を MySQL テーブルに保存します。

CREATE TABLE blacklist(
    `ip_address` VARCHAR(35) NOT NULL,
    `failures` INTEGER DEFAULT 0,
    `release_time` BIGINT DEFAULT -1,
    PRIMARY KEY(`ip_address`)
);

ログイン チェックでは、最初に次のクエリを使用して、現在の時刻より前のリリース時刻を持つブラックリスト エントリを削除します (リリース時刻が既に過ぎている場合)。

/* I pass in time() */
DELETE FROM failures WHERE release_time < ?;

次に、次を実行します。

/* I pass in $_SERVER['REMOTE_ADDR'] */
SELECT failures FROM blacklist WHERE ip_address=?

行を取得しない場合、または返される $row['failures'] が 5 を超える場合は、ユーザー名とパスワードを確認できます。それ以外の場合は、ログインを完全に拒否します。

ログイン試行が失敗するたびに (ブラックリスト ルールまたは無効なユーザー名/パスワードによる)、次のコマンドを実行します。

/* IP address is $_SERVER['REMOTE_ADDR'],
   release_time is current time + (new failures * 90 minutes) */
INSERT INTO BLACKLIST(ip_address, failures, release_time) VALUES(?,?,?) 
ON DUPLICATE KEY UPDATE failures=failures+1, release_time=?;

残念ながら、少なくとも 3 回はデータベースにアクセスしています (ブラックリストのクリア、IP アドレスの取得、最小限の失敗の増加)。おそらく毎分キャッシュに書き込むなど、動的なブラックリストを維持するためのより良い方法はありますか?

php/mysql を使用した IP による禁止は私の質問に似ていることがわかりましたが、ログインの試行をかなりの期間停止した場合、ブラックリストから削除できるようにしています。このように、認証情報を単純に忘れた人は、力ずくで認証情報を取得しようとする人よりも影響が少なくなります。

4

1 に答える 1

1

次のクエリは定期的に実行する必要はなく、cronジョブに移動できます。

DELETE FROM failures WHERE release_time < ?;

この「ブール」クエリは、その人がブラックリストに登録されている場合は1を返し、それ以外の場合は0を返します。

SELECT
  COUNT(ip_address) as blacklisted
FROM blacklist
WHERE
  ip_address = ? AND
  release_time > ? AND
  failures > 5

PHPを使用せずに行をカウントし、数値を比較すると、処理が高速化される可能性があります。

if ($row['blacklisted']) { /* ... */ }

最後のものは本当に避けられないと思います。

于 2012-09-20T13:48:30.503 に答える