WordPress のサイト内検索を利用した SPAM
WordPress のサイト内検索を利用した悪質な SPAM 行為ですが、SEO 的にもマイナスになる可能性があるので対策は必須です。
これまではテーマ側で noindex して済ませていました。Googleの SEO としてはそれで OK ですが周囲で俄に増加傾向にあることもあって、踏み台にされるんじゃないかという怖れから、しっかりとした対策を講じることとしました。そもそも、検索 SPAM 対策は本来 WordPress の コアに組み込むべきだと思うんですが。
対策の骨子は2つあります。
- 検索文字数の制限
- Akismet を利用した SPAM 判定
まず文字数は、大半のSPAMが長い文字列を使ってきていることから、有効性が高いと言えます。私の設置した感じではこれで7割くらいの SPAM がひっかかっていました。
次に Akismet の SPAM チェックを援用します。もちろん Akismet のインストール&有効化が必要です。日本向けのサイトの場合はあまり大きな効果が見込めないので外してもいいかも。
これらの制限に引っかかったクエリの表示には 500 ステータスを返そうというわけです。効率を重視するスパマーなら(そんなものがいればですが)これで寄ってこなくなるかも知れません。
コード
functions.php に丸写しで動くはず。
add_action( 'parse_query', function ( $query ) {
if ( defined( 'REST_REQUEST' ) && REST_REQUEST || defined( 'DOING_AJAX' ) && DOING_AJAX || is_admin() || !$query->is_main_query() || !$query->is_search ) return;
$search_query = $query->get( 's' );
if ( !$search_query ) return;
// 文字数制限
if ( strlen( $search_query ) > 80 && mb_strlen( $search_query ) > 40 ) { // 半角80文字 & マルチバイト約40文字
status_header( 500 );
exit;
// $query->set_404();
// status_header( 404 );
}
// Akismet による SPAM チェック Akismet使ってない人は不要
if ( class_exists( 'Akismet' ) && Akismet::get_api_key() ) {
$user_ip = isset( $_SERVER['HTTP_X_REAL_IP'] ) ? $_SERVER['HTTP_X_REAL_IP'] : ( isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ? trim( current( preg_split( '/,/', $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) ) : $_SERVER['REMOTE_ADDR'] );
$akismet_fields = http_build_query( array(
'blog' => esc_url( home_url() ),
'blog_lang' => get_locale(),
'comment_type' => 'search_query',
'comment_content' => sanitize_text_field( $search_query ),
'contact_form_subject' => sanitize_text_field( $search_query ),
'comment_author_IP' => $user_ip,
'user_ip' => $user_ip,
'referrer' => sanitize_text_field( $_SERVER['HTTP_REFERER'] ?? '' )
) );
$response = Akismet::http_post( $akismet_fields, 'comment-check' );
if ( 'true' == $response[1] ) {
status_header( 500 );
exit;
// $query->set_404();
// status_header( 404 );
}
}
});
文字数制限のところは、任意に変更してください。サイトの性質によっては、もっと長い方がいいかもですし、逆に余計なリソースは使いたくなければ、もう少し厳しめでいいでしょう。
返却するヘッダステータスはサーバーやサイトのリソースの削減のため 500 にしていますが、検索することに比重を置いたデータベースサイトなどの場合は、404 にしてテンプレートで表示をコントロールする方がユーザーに優しく設計できるでしょう。その場合は、status_header(500) と exit を削除して$query->set_404() と status_header( 404 ) をセットしてください。