WordPressで作ったサイトが乗っ取られた!?復旧までの全作業
いくつかのWordPressのサイトの管理を行っているのですが、その中で、放置気味となっているサイトが乗っ取りにあいました。復旧までの全作業を公開していこうと思います。
原因は当然自業自得なわけで、アホだなーと笑いながら見てください。
また同じような被害にあった方への参考になれば幸いです。
今回被害にあった環境
OS:VPS上でCentOS release 6.10 (Final)
PHP:PHP 5.3.3 (cli) (built: Mar 22 2017 12:27:09)
WordPress:バージョン 5.1.1–ja
※PHP5系のサポートは2018年で終わっています。WordPressでもPHP7系が推奨されています。またCentOS6は2020/11/30にメンテナンスアップデートが終了となります。
※環境が古いことは前々から認識しており、今回被害にあったサイト以外は、最新のKUSANAGI環境へ移行済みでした。忙しかったからと言ってメンテナンスをサボっていた罰が当たったのでしょう。
乗っ取りに気が付く
気が付いたのは、WordPressから新規ユーザー登録のメールが届いたからです。
え!?何が起きた!?
サーバーがクラックされた?WordPressの管理者アカウントが漏れた?
とりあえずWordPressの管理画面にアクセスするも、海外サイトへ転送されて全くアクセスできません。あらーやられたわー。
あまり使っていないサイトとはいえ乗っ取られたらやっぱり焦ります。
原因究明
- 全ファイルバックアップ
VPSへのアクセスは正常でした。サーバー全体が乗っ取られたわけではなさそうだったので少し安心。
とりあえず現状を保存しよう!ということですべての関連ファイルをローカルへバックアップ - DNSサーバー確認
サーバーのAレコードに異常なし。 - .htaccessの確認
.htaccessに異常なし。 - apacheの設定確認
confファイル等に異常なし。apacheの再起動しても状況変わらず。 - Fiddlerでサイトの詳細を確認
Fiddlerにてサイトの状況を確認。各種ファイルのリンク(jsやcssなども)先が「setforconfigplease.com」になっているのを確認。これが海外サイトへの転送になっていると推測。 - サイト内ファイルとmysqlのデータの確認
サイト内の全データと、mysqlからエクスポートした全データから「setforconfigplease.com」を含むファイルを検索するも見つからず。 - 悩む
setforconfigplease.comをググってもそれらしき情報も出ず。ファイルからもSQLからもそれらしき跡がない。
少し悩む。そして、落ち着いて順番に少しずつ手探りで確認しようということに。 - サイト内のhtmlファイルへアクセス
WordPressのreadme.htmlなどは普通に読めるので、サーバーやapacheの設定のせいではなくPHP上で何かが起きていると推測。 - テーマファイルの無効化・再インストール
テーマファイルを無効化・再インストールするも変わらず。 - プラグインの無効化
プラグインをすべて無効化してみるも変わらず。 - WordPressの再インストール
新規インストールしたWordPressは正常稼働。しかし障害のあった時のwp-config.phpを戻してMySQLとつなぐと現象再発。
この時点でほぼDB内に何かトラブルがあると推測。 - DB内を確認
wp_options内のsiteurlとhomeが「https://getmyfreetraffic.com/・・・・」に書き換えられている!!!原因はこいつか!!!
ということで正しいURLに書き換え。 - 復活!
WordPressへのログイン、サイトの表示が復帰。
結局ここまで2時間近くかかりました。
復旧後行った作業
今回の被害の原因
結局、書き換えられたのはWordPressアドレスとサイトアドレスだけで、管理者アカウントやコンテンツには全く被害がなく、復旧は思ったより早く済みました。
結局不正なユーザーが作られた原因は、
- 設定がおかしかった
「メンバーシップ」が「だれでもユーザー登録ができるようにする」
「新規ユーザーのデフォルト権限グループ」が「管理者」
となっていた。 - アカウント情報が漏れた
- PHPのバージョンが古い
だと思います。
WordPressの「メンバーシップ」と「デフォルト権限グループ」は、標準でこの設定にはなっていないのですし、自分が設定した覚えもないので、現時点でなぜ不正ユーザー登録がされたのか分かっていません。
まとめ
WordPressの設定で 「メンバーシップ」が「だれでもユーザー登録ができるようにする」「新規ユーザーのデフォルト権限グループ」が「管理者」となっていると簡単に管理者ユーザーが作れてしまい、乗っ取られます。注意しましょう。
サイトが無条件で転送されてしまうときはwp_optionsのhomeとsiteurlもすぐ確認しよう。
サーバーの更新はちゃんとやろう。
ということでいい教訓となりました。
さくらVPSを長年使っている私が、ConoHaVPSを褒めてみる。
前提
さくらのVPSをCentOS 6/7で何台か運用しています。
Apache,Nginx,MySQL,MariaDB,PHP5/7,HHVMなどを使用し、WordPress・KUSANAGIで数十ドメインをホストしています。
ConoHaを試しに使ってみた理由
DNSサーバーをNSDで運用していたが、ドメイン変更のたびにVPSにログオンして設定ファイル編集するの面倒。さくらのVPSのネームサーバーの無料枠は制限があり、ならいっそのことDNSのドメイン数に制限のないConoHaにしてみよう!ってことで。
さくらとConoHaの比較をされている方は多いと思いますが、どちらを選んでも性能的に問題なく優秀だと思います。
ConoHaを使ってみて良かったところ
- DNSのドメイン数が無制限
今回のConoHaを試した理由。そしてConoHaの管理画面の方がみやすい感じがする。 - VPSの管理にAPIが使える
全DNSのゾーンファイルをエクスポートするスクリプトを動かしています。APIがあるのは助かります。 - VPSの自動バックアップがある
さくらのVPS使用当初はMondo Rescueを使って全体のバックアップをしていましたが、リストアする際のISOアップロード容量が10GBなのでシステムとデータを分けてバックアップするなど工夫が必要で面倒でした。
ConoHaなら有料だが週1で3世代のバックアップを設定画面からポチっとするだけ。リストアも簡単。
欲をいえばバックアップ頻度や世代数を設定できれば最高。 - アプリがある
ConoHa Mobileというアプリがあり、サーバーの状態がスマホですぐ確認できる。さくらでもVPSコントロールパネルにWEBでログインすればいいが、やっぱりアプリのが手軽
まだConoHa VPSを使い始めて数か月ですが、何も問題なく快適です。これからもさくらとConoHaと両方使っていこうと思います。
性能的にも金額的にもあまり差がないため、どちらか迷っている人は決めかねると思いますが、美雲このはか桜葉愛の好みの方にすればいいんじゃないかな?
追記
バックアップのMondo RescueのI/O負荷高いけど大丈夫か?とご心配をいただきました。
私は全データではなく、システムの大事なところだけ最小限バックアップし、負荷の高いと言われてる時間帯はなるべく避けてメンテナンスするようにしています。
VPSのバックアップはMondoRescueを使うという記事多いですが、I/Oの制限に引っかからないようにご注意ください。
ASP.NET IdentityでRoleを使う手順
ASP.NET Identity 2.0とは?
ASP.NET Identity 2.0が登場し、Visual Studio 2013の標準テンプレートに組み込まれるようになりました。
ONE ASP.NETでMVCでもWebAPIでも使え、OWINでソーシャル連携ログイン、nugetでも簡単にインストールできるようになりました。
が、今までのASP.NETフォーム認証と似ているようで、設定方法など全く別物になりました。
基本的なことは以下のサイトをご覧いただけるとわかると思います。
ASP.NET Identity入門:CodeZine(コードジン)
ただ単にユーザーの登録、ログインするだけなら、標準テンプレートで十分使えると思います。
ロールはどこに?
フォーム認証の頃から、ロールベースのアクセス制御ができたのですが、今のテンプレートにはロールに関するコードありません。
いくつかコードを追加するだけで使えるようになるので、まとめておきます。MVC 5でのコードです。
Models/IdentityModels.cs
public class ApplicationRole : IdentityRole { }
App_Start/IdentityConfig.cs
public class ApplicationRoleManager : RoleManager<ApplicationRole, string> { public ApplicationRoleManager(IRoleStore<ApplicationRole, string> store) : base(store) { } public static ApplicationRoleManager Create(IdentityFactoryOptions<ApplicationRoleManager> options, IOwinContext context) { var manager = new ApplicationRoleManager(new RoleStore<ApplicationRole>(context.Get<ApplicationDbContext>())); return manager; } }
App_Start/Startup.Auth.cs
public partial class Startup { // 認証設定の詳細については、http://go.microsoft.com/fwlink/?LinkId=301864 を参照してください public void ConfigureAuth(IAppBuilder app) { app.CreatePerOwinContext(ApplicationDbContext.Create); app.CreatePerOwinContext<ApplicationUserManager≥(ApplicationUserManager.Create); // このコードを追加 app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create); } }
Controllers/AccountController.cs
public class AccountController : Controller { private ApplicationUserManager _userManager; private ApplicationRoleManager _roleManager; public AccountController() { } public AccountController(ApplicationUserManager userManager, ApplicationRoleManager roleManager, ApplicationSignInManager signInManager) { UserManager = userManager; RoleManager = roleManager; SignInManager = signInManager; } public ApplicationRoleManager RoleManager { get { return _roleManager ?? HttpContext.GetOwinContext().Get<ApplicationRoleManager>(); } private set { _roleManager = value; } } }
これでビルドするとAccountController上でRoleManagerがつかえるようになります。
すでにDBが作成されている場合サーバーエラーが発生します。
データベースの作成後、'ApplicationDbContext' コンテキストの背後にあるモデルが変更されました。Code First Migrations を使用したデータベースの更新を検討してください (http://go.microsoft.com/fwlink/?LinkId=238269)。
説明: 現在の Web 要求を実行中に、ハンドルされていない例外が発生しました。エラーに関する詳細および例外の発生場所については、スタック トレースを参照してください。
この場合データベースの更新が必要です。
パッケージマネージャで以下のコマンドを実行します。
PM> Enable-Migrations コンテキストが既存のデータベースを対象にしているかをチェックしています... データベース初期化子で作成されたデータベースが検出されました。既存のデータベースに対応する移行 '201410121217026_InitialCreate' がスキャフォールディングされました。代わりに自動移行を使用するには、Migrations フォルダーを削除し、-EnableAutomaticMigrations パラメーターを指定して Enable-Migrations を再実行します。 Code First Migrations がプロジェクト WebApplicationIdentity で有効になりました。 PM> Add-Migration "AddRole" 移行 'AddRole' をスキャフォールディングしています。 この移行ファイルのデザイン コードには、現在の Code First モデルのスナップショットが含まれています。このスナップショットは次の移行をスキャフォールディングする際、モデルに対する変更の計算に使用されます。モデルに追加の変更を行い、この移行に含める場合は、'Add-Migration AddRole' を再実行して再度スキャフォールディングできます。 PM> Update-Database ターゲット データベースに適用されている SQL ステートメントを表示するには、'-Verbose' フラグを指定します。 明示的な移行を適用しています: [201410121336408_AddRole]。 明示的な移行を適用しています: 201410121336408_AddRole。 Seed メソッドを実行しています。
すでに別のEntity Frameworkでcontextが作成されている場合は、Enable-Migrations -ContextTypeName [context名]で、Context名を指定できますので、ApplicationDbContextを指定してください。
ロール(RoleManager)を使う
RoleManager.Rolesプロパティでロールの一覧が取得できます。
RoleManager.RoleExistsメソッドで存在確認、Createメソッドで作成ができます。
~Asyncもありますので必要な方を使ってください。
ユーザーとロールの関連は、UserManager.AddToRole、AddToRoles、GetRoles、IsInRole、RemoveFromRole、RemoveFromRolesメソッドなどで操作できます。
mvcのコントローラーでロールのアクセス制御をする場合は、依然と同様で、
[Authorize(Roles = "ロール名")]
で使用できます。
ASP.NET関連本
プログラミング MICROSOFT ASP.NET4 (Microsoft Press)
- 作者: ディノエスポシト,クイープ
- 出版社/メーカー: 日経BP社
- 発売日: 2012/01/26
- メディア: 単行本
- 購入: 2人 クリック: 8回
- この商品を含むブログ (4件) を見る
昔書いたコードのEntityFrameworkを6.0にバージョンアップしたら、いろいろ困ったという話
昔書いたコードのEntityFrameworkを6.0にバージョンアップして、
モデルを作り直したら、ObjectContextからDbContextへ変わってしまって、対応に追われました。
コードの修正したので結果を書いておきます。
何がどう変わったのか
Entity Framework 4.1でDbContext APIが追加され、軽量なDbContextクラスが追加されました。
2011年ごろだったと思いますので、すでに3年前のことです。
ADO.NET Entity Framework 4.1 における Code First
まずEntityFrameworkのバージョンと、データベースファーストでのObjectContext/DbContextの関係を整理します。
EF4.0までは、ObjectContext
EF5では、.NET 4.5の場合DbContext、.NET 4.0の場合はObjectContext(EFのバージョンは4.4でした)
EF6では、.NET 4.0でもDbContextとなりました。
なんでこんな複雑なことになっているのかは、EF5が、.NET4.5のコアに関連したようですが、EF6でそれが解消されたようです。
Entity Framework 5 のパフォーマンスに関する考慮事項
Entity Framework 6: 上級者向けエディション
バージョンアップしてモデルを作り直したら何が起きたか?
ほとんどは問題ないのですが、一部整理された部分があるので、そこだけコードの修正が必要です。
修正はめんどうですが、整理されてわかりやすくなっていると思います。
SQLコマンドの実行
ObjectContext.ExecuteStoreCommand メソッド から
DbContext.Database.ExecuteSqlCommand メソッド へ変わりました。
何かデータベースへ作用させるものは、dbContext.Databaseへまとめたということのようです。
当然CommandTimeoutなんかも移動しています。
変更の追跡
ObjectContext.ObjectStateManager プロパティ から
DbContext.ChangeTracker プロパティ へ変わりました。
GetObjectStateEntries()とか長い名前がEntries()になり、
HasChanges()なんかもついて、スッキリ便利になってます。
データベースのオプション
ObjectContext.ContextOptions プロパティ から
DbContext.Configuration プロパティ に変わりました。
エンティティーセットとクエリ
ObjectContext.ObjectSet<TEntity>から
DbContext.DbSet<TEntity>に変わりました。
エンティティーセットをWhereしてみると結果が
ObjectQuery<T>から
IQueryable<T>に変わりました。
SQLクエリの実行が
ObjectContext.ExecuteStoreQueryから
DbSet<TEntity>.SqlQueryに変わりました。
Windows FormsのBindingSource
ここが少し面倒でした。
今まではそのままクエリ結果等をDataSourceへ渡すだけでよかったのですが、
EntityFrameworkを実行すると、System.NotSupportedExceptionが発生します。
追加情報:ストア クエリ (DbSet、DbQuery、DbSqlQuery、DbRawSqlQuery) への直接のデータ バインドはサポートされていません。
代わりに、DbSet で Load を呼び出すなどして DbSet にデータを設定し、ローカル データにバインドしてください。
WPF の場合は DbSet.Local に、WinForms の場合は DbSet.Local.ToBindingList() にバインドします。
ASP.NET WebForms の場合は、クエリで ToList() を呼び出した結果にバインドしたり、モデル バインドを使用したりできます。
詳細については、http://go.microsoft.com/fwlink/?LinkId=389592 を参照してください。
だそうです。
結局どうすればいいのかというところですが、
データ取得のみの場合には、ToList()などでList<T>にしてしまえば問題ありません。
更新するデータソースの場合は、DbSet<TEntity>.Local プロパティが追加されていますので、それをDataSourceへ渡してあげればOKです。
その際あらかじめ、DbSet<TEntity>.Load()で読み込んであげてください。
あとはそのままで大丈夫でした。
DbSet<TEntity>.SqlQueryメソッドで取得したDbSqlQuery<TEntity>はLocalがありません。
そのままDataSourceへ渡してもエラーが出ます。
この場合は、ObservableCollectionを作成し、コンストラクタでDbSqlQuery<TEntity>を渡して、
作成したObservableCollectionをDataSourceへ渡してあげればOKです。
ここでしばらく嵌りました。
よくよく思い返してみれば、データアクセスの技術ってかなりの頻度で更新されてますね。
業務システムだと結構重要なところなので、非常に便利なのはいいけれど、コードの修正は大変です。
ADO.NETのDataSetとかの時代のプログラムをEntityFrameworkで書き直す気は起きません・・・。
Microsoft ADO.NET Entity Framework Step by Step (Step by Step Developer)
- 作者: John Paul Mueller
- 出版社/メーカー: Microsoft Press
- 発売日: 2013/08/15
- メディア: Kindle版
- この商品を含むブログを見る
Programming Entity Framework: DbContext
- 作者: Julia Lerman,Rowan Miller
- 出版社/メーカー: Oreilly & Associates Inc
- 発売日: 2012/03
- メディア: ペーパーバック
- クリック: 1回
- この商品を含むブログを見る
Entity Framework 6 Recipes (Recipes Apress)
- 作者: Brian Driscoll,Nitin Gupta,Rob Vettor,Zeeshan Hirani,Larry Tenny
- 出版社/メーカー: Apress
- 発売日: 2013/10/29
- メディア: ペーパーバック
- この商品を含むブログを見る
Entity Framework 4.0 Recipes: A Problem-Solution Approach (Expert's Voice in .NET)
- 作者: Larry Tenny,Zeeshan Hirani
- 出版社/メーカー: Apress
- 発売日: 2010/05/15
- メディア: ペーパーバック
- この商品を含むブログを見る
- 作者: Dr. Holger Schwichtenberg,Manfred Steyer
- 出版社/メーカー: Microsoft Gmbh
- 発売日: 2014/05/15
- メディア: ハードカバー
- この商品を含むブログを見る
ITシステムの安定性が高いと、顧客満足度が下がってしまうのか?というお話
ITシステムはトラブルがなくて安定的に使える方がいい。
当たり前です。誰でもそうだということでしょう。
トラブルが発生し、それを解消すると喜ばれるというのも事実。
(もちろんトラブルが多すぎれば、悪印象なのは当然です。)
安定したシステムはそれがない。=喜ばれる機会が少ない。
では、適度にトラブルがあり、それを解消していくことが一番顧客満足度が高いのか?となってしまいます。ITのみならず、ほかの業種にも言えることだと思います。
一発で完璧な仕事をする人と、何度も修正修正しながら仕事をする人。
どちらがいいのでしょうか?
技術者の威信にかけて、安定したシステムを作りたい。
が、こういったジレンマに陥ることもけっこうあります。
不思議ですね。安定している方がいいに決まっているのに・・・。
Windows Server 2008 Hyper-VでVHDの最適化するときにエラーが発生した場合の対処(追加)
Windows Server 2008 Hyper-VでVHDの最適化するときにエラーが発生した場合の対処
このケースでも最適化できないケースが発生してしまいました。
が、ボリュームシャドーコピーを削除後、ディスクの最適化をすることで解消しました。
The Microsoft Conference 2013 Days2まとめ
Days 1まとめをご覧ください。
ほぼ1日開発系セッションに居座ってました。
開発者向けキーノート のCloud First, Mobile First, Developer First !というのがとてもよくマイクロソフトの行く先を示していると感じました。
思い出せば約1~2年前、
Windows Phoneが迷走しだし、Windows 8のスタートメニュー除去に関する不評、それに加えて日本においてのiOSの躍進から、マイクロソフトは大丈夫なのか?と不安に思っていました。
しかし、MSC2013に参加して、それらの不安がかなり払拭されました。
開発者として、マイクロソフトを支持する4つの理由。
1.VS2013は地味に良い改良が加えられている。
2.Windows Azureは必要なサービスがほぼ整って使わない理由が見つからない。
3.オープンな技術や、他社のデバイス、他社のサービスとの連携にも積極的な姿勢。
4.エンタープライズ品質。
ただし、2013年末時点で、ですがね。
あとイベント自体に苦言があるとすれば、セッションの立見がかなり頻発していたのはちょっとまずいのではないのかな?ただでさえ2日間かんづめで疲れているのに。