こんにちはー!ニアです。
このブログではWordPressのセキュリティ対策として、ログイン履歴を残すためにプラグイン「Crazy Bone(狂骨)(→Github)」を入れており、先日はADO.NETとLINQを使って、ログインエラー時のユーザー名とパスワードを取り出した記事をQiitaに書きました。
今回はデータ解析に特化したR言語を使って、MySQLデータベースからエクスポートしたCSVファイルを読み込み、分析してみました。
1. 実行環境
今回はR for Windows 3.2.2を使用しました。また、使用したパッケージは以下の2つです。
- data.table
- stringr
2. R言語を使って、ログイン履歴を分析
2.1. CSSファイルを読み込み、ログインエラーのレコードを抽出
まずは、fread関数を使ってCSVファイルを読み込みます。先頭行はフィールド名なので、headerをTRUEに、encodingはUTF-8を指定します。
次にactivity_statusフィールドをキーに条件式を使って、値が「login_error」であるレコードを抽出します。
# wp_user_login_log.csvを読み込みます。
linlog <- fread( "wp_user_login_log.csv", header = TRUE, encoding = "UTF-8" )
# activity_statusフィールドの値がlogin_errorのレコードを抽出します。
linerr <- linlog[linlog$activity_status == "login_error"]
これで、ログインエラー時のdata.tableオブジェクトができました。
2.2. ユーザー名とパスワードを取り出す。
ログインエラー時のユーザー名とパスワードはactivity_errorsフィールドに格納されていますが、値がPHPのシリアライズ形式なので、正規表現を使って取り出します。
a:3:{
s:6:"errors";
a:1:{
s:16:"invalid_username";
a:1:{
i:0;s:177:"<strong>エラー: 無効なユーザー名です。 <a href="[ブログのアドレス]/wp-login.php?action=lostpassword">パスワードをお忘れですか ?</a>";
}
}
s:10:"user_login";
s:5:"admin";
s:13:"user_password";
s:3:"123";
}
a:3:{
s:6:"errors";
a:1:{
s:16:"invalid_username";
a:1:{
i:0;s:177:"<strong>エラー: 無効なユーザー名です。 <a href="[ブログのアドレス]/wp-login.php?action=lostpassword">パスワードをお忘れですか ?</a>";
}
}
s:10:"user_login";
s:8:"wpengine";
s:13:"user_password";
s:8:"password";
}
まずは「s:10\:””user_login””;s\:\d*\:””.*?””; 」及び「s:10\:””user_login””;s\:\d*\:””.*?””;」のパターンとstr_match関数を使って、activity_errorsフィールドの値から「s:10:”user_login”;s:\d:”ユーザー名”;」及び「s:13:”user_password”;s:\d:”パスワード”;」の形で取り出します。
次に「s:10\:””user_login””;s\:\d*\:””|””; 」及び「s:10\:””user_login””;s\:\d*\:””|””;」のパターンとgsub関数を使って、余分な文字列「s:10:”user_login”;s:\d:”」や「s:13:”user_password”;s:\d:”」、「”;」を取り除き、ユーザー名及びパスワードを取り出します。
# ログインエラー時のユーザー名及びパスワードを取り出すための正規表現です。
usrrep1 <- c( "s:10\\:\"\"user_login\"\";s\\:\\d*\\:\"\".*?\"\";" )
usrrep2 <- c( "s:10\\:\"\"user_login\"\";s\\:\\d*\\:\"\"|\"\";" )
passrep1 <- c( "s:13\\:\"\"user_password\"\";s\\:\\d*\\:\"\".*?\"\";" )
passrep2 <- c( "s:13\\:\"\"user_password\"\";s\\:\\d*\\:\"\"|\"\";" )
# ログインエラー時のユーザー名及びパスワードを取り出します。
errusr <- gsub( usrrep2, "", str_match( linerr$activity_errors, usrrep1 ) )
errpass <- gsub( passrep2, "", str_match( linerr$activity_errors, passrep1 ) )
そして、ユーザー名とパスワードのベクトルからdata.tableを作成します。
# ユーザー名とパスワードのベクトルからdata.tableを作成します。
errtable <- data.table( data.frame( User = errusr, Pass = errpass ) )
print( "自分のブログへのログインエラーの概要" )
print( summary( errtable ) )
試しにsummary関数を使ってみると、ログインエラー時のユーザー名とパスワードそれぞれの試行回数(TOP5)が表示されます。
作成したdata.tableからユーザ名、パスワードでそれぞれグループ化し、.Nで試行回数をカウントします。さらにorder関数で試行回数の多い順にソートします。
# ユーザー名、パスワードでグループ化し、試行回数をカウント。さらに試行回数が多い順にソートします。
errusrs <- errtable[ , .N, by = User ][ order( -N ) ]
errpasses <- errtable[ , .N, by = Pass ][ order( -N ) ]
print( errusrs )
print( errpasses )
◆ ソースファイル
library( data.table )
library( stringr )
# wp_user_login_log.csvを読み込みます。
linlog <- fread( "wp_user_login_log.csv", header = TRUE, encoding = "UTF-8" )
#setkey( linlog, activity_status, activity_errors )
# activity_statusフィールドの値がlogin_errorのレコードを抽出します。
linerr <- linlog[linlog$activity_status == "login_error"]
# ログインエラー時のユーザー名及びパスワードを取り出すための正規表現です。
usrrep1 <- c( "s:10\\:\"\"user_login\"\";s\\:\\d*\\:\"\".*?\"\";" )
usrrep2 <- c( "s:10\\:\"\"user_login\"\";s\\:\\d*\\:\"\"|\"\";" )
passrep1 <- c( "s:13\\:\"\"user_password\"\";s\\:\\d*\\:\"\".*?\"\";" )
passrep2 <- c( "s:13\\:\"\"user_password\"\";s\\:\\d*\\:\"\"|\"\";" )
# ログインエラー時のユーザー名及びパスワードを取り出します。
errusr <- gsub( usrrep2, "", str_match( linerr$activity_errors, usrrep1 ) )
errpass <- gsub( passrep2, "", str_match( linerr$activity_errors, passrep1 ) )
# ユーザー名とパスワードのベクトルからdata.tableを作成します。
errtable <- data.table( data.frame( User = errusr, Pass = errpass ) )
#print( "自分のブログへのログインエラーの概要" )
#print( summary( errtable ) )
# ユーザー名、パスワードでグループ化し、試行回数をカウント。さらに試行回数が多い順にソートします。
errusrs <- errtable[ , .N, by = User ][ order( -N ) ]
errpasses <- errtable[ , .N, by = Pass ][ order( -N ) ]
print( errusrs )
print( errpasses )
◆ 実行結果
3. おわりに
今回初めてR言語を使ってみました。data.tableパッケージを使うだけでCSVファイルをテーブル形式として読み込めるのがいいですね。
今度はグラフのプロットや簡単な画像処理をやってみようかな。
[END]
コメント