このiRuleはユーザ名によってPOST回数を数えるため、HTTPのBasic認証を利用しているサイトでの利用が必須です。

タイトル:POSTのレート制限

機能:

*HTTP Basic認証に含まれるユーザ名を取得
*ユーザ毎のレート(許可するPOSTの回数)を適用し、(Data Groupに)登録していないユーザはグローバルレートを適用
*ウィンドウの時間内に、POST回数をカウントアップ(ユーザ毎のカウンタを利用)
*レート値を超えた場合、501エラーをユーザへ返答

ベネフィット:

*掲示板などのサイトの大量投稿を防止

使い方:

*MaxPOSTRatesのData Groupで特定ユーザのPOST回数(例:管理者やVIPユーザなど)を設定
*RULE_INITで一般ユーザのPOST回数及びウィンドウサイズ(秒)を設定

注意点:

*下記デフォルトiRuleでは、レート値を超えた場合に返答する501エラーの内容が空状態です。
内容をカスタマイズするには、HTTP::respond 501の後に「content "内容"」を追加してください。

【データグループ部分 - GUIのiRules→Data Groupsで設定、
 或いは下記のテキストをbigip.confに追加】

class MaxPOSTRates {
  #HTTP Basic認証のユーザ名  最大のPOST回数
  "DAllen 20"
  "JCaples 10"
  "CWalker 10"
  "AGerace 20"
}


 

【iRule部分】
#
# Deb Allen, F5 Networks
# April 2006
# Tested on LTM v9.2.2 and 9.2.3
#

when RULE_INIT {
  set ::maxRate 10              #ユーザ設定が存在しないときに利用する値
  set ::windowSecs 10           #ウィンドウサイズ(秒)

  #配列が存在する場合、一旦削除してから作成

  array unset ::postHistory
  array set ::postHistory { }
}
when HTTP_REQUEST {
  if { [HTTP::method] eq "POST" } {
    if {[HTTP::header exists Authorization]} {
      #AuthorizationヘッダからB64エンコードされたユーザ名を取得し、デコードしユーザ名を保存
      set myUserID [getfield [b64decode [substr [HTTP::header exists Authorization] 6 end]] ":" 1]
      #Data Groupからユーザ名についているPOST回数を利用
      set myMaxRate [findclass $myUserID $::MaxPOSTRates " "]
      #Data Groupにユーザが存在しない場合、グローバルレートを利用
      if { $myMaxRate eq "" }{
        set myMaxRate $::maxRate
      }
    } else {
      #Authorizationヘッダが存在しない場合、認証されていないエラーを返答
      HTTP::respond 401
      return
    }
    set currentTime [clock seconds]
    #現在時刻よりウィンドウのスタート時刻を計算
    set windowStart [expr {$currentTime - $::windowSecs}]
    #現在のユーザIDに対してのPOSTをカウントアップ
    set postCount 0
    #ウィンドウ内に投稿されたPOSTをカウントし、ウィンドウより古い時刻で投稿されたPOSTの記録を廃止
    foreach { requestID requestTime } [array get ::postHistory ${myUserID}*] {
      #POST時刻 > $windowStartのみをカウント
      if { $requestTime > $windowStart } {
        incr postCount 1
      } else {
        unset ::postHistory($requestID)
      }
    }
    if { $postCount < $myMaxRate } {
      #POST許可する場合、乱数でユニーク番号をrequestIDとし、POST時刻とともに配列に保存
      set requestID "${myUserID}.[expr { int(10000000 * rand()) }]"
      set ::postHistory($requestID) $currentTime
    } else {
      #POSTを拒否する場合、501エラーを返答
      log local0. "Service Unavailable - User $myUserID - Current rate: $postCount - Max rate: $myMaxRate"
      HTTP::respond 501
      return
    }
  }
}


※F5ネットワークスジャパンでは、サンプルコードについて検証を実施していますが、お客様の使用環境における動作を保証するものではありません。実際の使用にあたっては、必ず事前にテストを実施することを推奨します。