(130) IPアドレスによりCGI実行を一定時間制限する。

投稿者: | 2025年4月26日

645 views

【1】やりたいこと

Web上で公開している CGIプログラムの中には、処理が重たいものもある。

このプログラムに高頻度でリクエストが届くとサーバ負荷が上がり・・・
共用サーバであればアカウントがBANされる恐れがある。

よって、
同じIPアドレスからのリクエストを一定時間拒否する実装を加えたい。

【2】やってみる

IPアドレスによるブロック処理を実装し、これを CGIの先頭で実行する。
アクセス履歴の管理には、簡易DBである SQLite3 を使うことにした。

import os
import time
import sqlite3

class IPBlocker:
    def __init__(self, db_path='/home/hoge/ip_access_log.db', block_seconds=10):
        self.db_path = db_path
        self.block_seconds = block_seconds
        self._init_db()

    # データベースとテーブルを初期化
    def _init_db(self):
        conn = sqlite3.connect(self.db_path)
        cur = conn.cursor()
        cur.execute('CREATE TABLE IF NOT EXISTS ip_access (ip TEXT PRIMARY KEY, last_access INTEGER)')
        conn.commit()
        conn.close()

    def check_ip(self):
        remote_ip = os.environ.get('REMOTE_ADDR', '')
        now = int(time.time())

        conn = sqlite3.connect(self.db_path)
        cur = conn.cursor()

        # 古いレコード削除
        cutoff_time = now - self.block_seconds
        cur.execute('DELETE FROM ip_access WHERE last_access < ?', (cutoff_time,))

        # 現在のIPの最終アクセス確認
        cur.execute('SELECT last_access FROM ip_access WHERE ip = ?', (remote_ip,))
        row = cur.fetchone()

        # レコードが存在 → block_seconds以内にアクセスあり → アクセス拒否
        if row:
            conn.close()
            print("Status: 429 Too Many Requests")
            print("Content-Type: text/plain\n")
            print("Too many requests. Please wait a few seconds.")
            exit(0)

        # 今回のアクセスを記録(INSERT OR REPLACE)
        cur.execute('REPLACE INTO ip_access (ip, last_access) VALUES (?, ?)', (remote_ip, now))
        conn.commit()
        conn.close()
#!/usr/bin/python
# -*- coding: utf-8 -*-

#-------------------------------->>> IPアドレスによる頻度制限
from ip_blocker import IPBlocker
IPBlocker().check_ip()
#--------------------------------<<< IPアドレスによる頻度制限

print("Content-Type: text/html; charset=utf-8\n")
 :
以下に CGIプログラムを書く。
 :

アクセス数(直近7日): ※試験運用中、BOT除外簡易実装済
  • 2026-04-19: 0回
  • 2026-04-18: 0回
  • 2026-04-17: 0回
  • 2026-04-16: 0回
  • 2026-04-15: 0回
  • 2026-04-14: 0回
  • 2026-04-13: 0回
  • コメントを残す

    メールアドレスが公開されることはありません。 が付いている欄は必須項目です