こんにちは、クラウドソリューション事業部の本田です。今回はWordPressのセキュリティに関するお話です。
別のレンタルサーバからAWSに移行されたいお客様で、AWS上でのサーバ構築をさせていただく機会が多くあります。その際によく気にされているのが、セキュリティ面です。 移行に合わせてよりセキュアな環境でWordPressを動かしたいという要望があり弊社ではよく以下の構成で構築させていただいています。
冗長化される場合は、EFSを使ったり、またはEC2をECSに置き換えるパターンもあります。
当然セキュリティグループを絞るなどそういった面での設定や対策はありますが、肝になってくるのはAWS WAFのルールをどのようなルールにするか、ということかと思います。元のサーバでは不正なアクセスへの対策が取られていなかったために、攻撃に遭ってしまった、乗っ取りに遭ってしまったなど色々とお話を聞くことがあります。そこで弊社的にこのルールが良いのでは?という弊社的ベストプラクティスなルールを考えてみました。あくまでも設定例となり、一般的な使い方をしているWordPressにおいては今回考えたルールが良いのではないかという内容ですので実際の適用時にはお客様の運用に合わせてルールを作成、選定しております。
ルールの方針
- マネージドルールを使う
- 管理画面へのアクセスもWAFのルールで制限する
1.マネージドルールを使う
対象が独自開発をしているサイトと違い多くのサイトで利用されているWordPressですので、汎用的な設定で問題ないと判断し、2の方針であるアクセス制限を除きマネージドルールを利用しています。詳細なロジックやルールについてはわからないというデメリットはありますがAWS側でアップデートされるためメンテナンスが不要というメリットがあります。スクラッチで開発しているシステムやWordPressでもかなりカスタマイズしている場合などですと、マネージドルールでも正常な動作に支障が出る可能性もありますので、事前に検証をオススメします。
2.管理画面へのアクセスもWAFで制限する
WordPressのプラグインやapache(Nginx)側の設定で、WPの管理画面へのアクセスを制限したりするなど色々と制限をする方法はありますが、保守をすることを考えると極力プラグインは使いたくなかったり、設定箇所がバラけてしまうと管理が煩雑になったりします。ですのでアクセスの制限も、WAFのルールを作って対応します。特定のURLは指定したIP アドレスからのアクセスでないとブロックしてしまうようなルールを作ります。
Cloudformationのテンプレート
今回Cloudformationのテンプレートから作成します。注意点としては、Cloudfrontで利用することを前提としていますので、バージニア北部リージョンで作成するようにしてください。他のリージョンで作成すると、エラーになり作成することができませんのでご注意ください。
1### AWS WAF
2Resources:
3# ------------------------------------------------------------#
4# IPset
5# ------------------------------------------------------------#
6# IPset Create
7 WAFv2IPSetdevelopper:
8 Type: "AWS::WAFv2::IPSet"
9 Properties:
10 Addresses:
11 - xxx.xxx.xxx.xxx/xx
12 IPAddressVersion: IPV4
13 Name: "IPSet-developper"
14 Scope: "CLOUDFRONT"
15# ------------------------------------------------------------#
16# WebACL
17# ------------------------------------------------------------#
18# WebACL Create
19 WordPressWebACL:
20 Type: AWS::WAFv2::WebACL
21 Properties:
22 Name: WordPressWebACL
23 Capacity: 11
24 Scope: CLOUDFRONT
25 DefaultAction:
26 Allow: {}
27 VisibilityConfig:
28 CloudWatchMetricsEnabled: false
29 MetricName: WordPressWebACL
30 SampledRequestsEnabled: true
31 Rules:
32 - Name: block-login-exclude-allow-ip
33 Action:
34 Block: {}
35 Priority: 1
36 Statement:
37 AndStatement:
38 Statements:
39 - NotStatement:
40 Statement:
41 IPSetReferenceStatement:
42 Arn: !GetAtt WAFv2IPSetdevelopper.Arn
43 - ByteMatchStatement:
44 FieldToMatch:
45 UriPath: {}
46 SearchString:
47 "wp-login.php"
48 TextTransformations:
49 - Priority: 0
50 Type: NONE
51 PositionalConstraint: CONTAINS
52 VisibilityConfig:
53 SampledRequestsEnabled: true
54 CloudWatchMetricsEnabled: true
55 MetricName: block-login-exclude-allow-ip
56 - Name: block-wp-admin-exclude-allow-ip
57 Action:
58 Block: {}
59 Priority: 2
60 Statement:
61 AndStatement:
62 Statements:
63 - NotStatement:
64 Statement:
65 IPSetReferenceStatement:
66 Arn: !GetAtt WAFv2IPSetdevelopper.Arn
67 - ByteMatchStatement:
68 FieldToMatch:
69 UriPath: {}
70 SearchString:
71 "wp-admin"
72 TextTransformations:
73 - Priority: 0
74 Type: NONE
75 PositionalConstraint: CONTAINS
76 VisibilityConfig:
77 SampledRequestsEnabled: true
78 CloudWatchMetricsEnabled: true
79 MetricName: block-wp-admin-exclude-allow-ip
80 - Name: allow-admin-from-allow-ip
81 Action:
82 Allow: {}
83 Priority: 3
84 Statement:
85 AndStatement:
86 Statements:
87 - IPSetReferenceStatement:
88 Arn: !GetAtt WAFv2IPSetdevelopper.Arn
89 - ByteMatchStatement:
90 FieldToMatch:
91 UriPath: {}
92 SearchString:
93 "wp-admin"
94 TextTransformations:
95 - Priority: 0
96 Type: NONE
97 PositionalConstraint: CONTAINS
98 VisibilityConfig:
99 SampledRequestsEnabled: true
100 CloudWatchMetricsEnabled: true
101 MetricName: allow-admin-from-allow-ip
102 - Name: AWSManagedRulesCommonRuleSet
103 Priority: 4
104 OverrideAction:
105 None: {}
106 VisibilityConfig:
107 SampledRequestsEnabled: true
108 CloudWatchMetricsEnabled: true
109 MetricName: AWSManagedRulesCommonRuleSetMetric
110 Statement:
111 ManagedRuleGroupStatement:
112 VendorName: AWS
113 Name: AWSManagedRulesCommonRuleSet
114 ExcludedRules:
115 - Name: SizeRestrictions_BODY
116 - Name: AWSManagedRulesAmazonIpReputationList
117 Priority: 5
118 OverrideAction:
119 None: {}
120 VisibilityConfig:
121 SampledRequestsEnabled: true
122 CloudWatchMetricsEnabled: true
123 MetricName: AWSManagedRulesAmazonIpReputationListMetric
124 Statement:
125 ManagedRuleGroupStatement:
126 VendorName: AWS
127 Name: AWSManagedRulesAmazonIpReputationList
128 ExcludedRules: []
129 - Name: AWSManagedRulesAnonymousIpList
130 Priority: 6
131 OverrideAction:
132 None: {}
133 VisibilityConfig:
134 SampledRequestsEnabled: true
135 CloudWatchMetricsEnabled: true
136 MetricName: AWSManagedRulesAnonymousIpListMetric
137 Statement:
138 ManagedRuleGroupStatement:
139 VendorName: AWS
140 Name: AWSManagedRulesAnonymousIpList
141 ExcludedRules: []
142 - Name: AWSManagedRulesWordPressRuleSet
143 Priority: 7
144 OverrideAction:
145 None: { }
146 VisibilityConfig:
147 SampledRequestsEnabled: true
148 CloudWatchMetricsEnabled: true
149 MetricName: AWSManagedRulesWordPressRuleSetMetric
150 Statement:
151 ManagedRuleGroupStatement:
152 VendorName: AWS
153 Name: AWSManagedRulesWordPressRuleSet
154 - Name: AWSManagedRulesSQLiRuleSet
155 Priority: 8
156 OverrideAction:
157 None: {}
158 VisibilityConfig:
159 SampledRequestsEnabled: true
160 CloudWatchMetricsEnabled: true
161 MetricName: AWSManagedRulesSQLiRuleSetMetric
162 Statement:
163 ManagedRuleGroupStatement:
164 VendorName: AWS
165 Name: AWSManagedRulesSQLiRuleSet
166 ExcludedRules: []
167 - Name: AWSManagedRulesPHPRuleSet
168 Priority: 9
169 OverrideAction:
170 None: {}
171 VisibilityConfig:
172 SampledRequestsEnabled: true
173 CloudWatchMetricsEnabled: true
174 MetricName: AWSManagedRulesPHPRuleSetMetric
175 Statement:
176 ManagedRuleGroupStatement:
177 VendorName: AWS
178 Name: AWSManagedRulesPHPRuleSet
179 ExcludedRules: []
こちらを作成すると以下のようなIPSetとルールが作成されます。
IPSet
Name | Description |
IPSet-developper | 開発関係者などのIPアドレス |
IPSetとは、特定のIPアドレスやIPアドレス範囲のリストであり、WAFのルールと組み合わせてホワイトリスト、ブラックリスト的な使い方ができます。今回の設定ではWordPressの管理画面へのアクセス(wp-login.phpと/wp-admin/)は、IPsetに登録されているIPアドレスからのアクセスのみ許可しますので、任意のIPアドレスを設定するようにしてください。
ルール(WebACL)
Name | Description |
block-login-exclude-allow-ip | 許可したIP以外からのwp-login.phpへのアクセスをブロックする |
block-wp-admin-exclude-allow-ip | 許可したIP以外からのwp-adminへのアクセスをブロックする |
allow-admin-from-allow-ip | 許可したIPからのwp-adminへのアクセスを許可する |
AWSManagedRulesCommonRuleSet | AWSマネージドの一般的な攻撃を防ぐルール(*) |
AWSManagedRulesAmazonIpReputationList | AWSマネージドのボットやその他の脅威に関連するソースをブロックするルール |
AWSManagedRulesAnonymousIpList | AWSマネージドのアプリケーションから身元を隠そうとする可能性のあるアクセスをブロックするルール |
AWSManagedRulesWordPressRuleSet | AWSマネージドのWP特有の攻撃を防ぐルール |
AWSManagedRulesSQLiRuleSet | AWSマネージドのSQL関連の攻撃を防ぐルール |
AWSManagedRulesPHPRuleSet | AWSマネージドのPHP特有の攻撃を防ぐルール |
(*)SizeRestrictions_BODYのみcountモードにしています。管理画面から画像などのファイルアップロードができないなど通常に操作に支障があったためcountに変更しています。
今回の設定では独自ルールが3つとAWSマネージドルールを6つ(AWSから始まる名前のルール)を使用しています。上位3つの独自ルールについては、マネージドルールではないためAWS側の仕様が変わったりした際には、内容を修正する必要がありますのでご注意ください。
AWSのマネージドルールについては、WordPressがapache、phpとmysqlで動くアプリケーションであるため、以下のルールを最低限入れておくのが良いかと思います。
- AWSManagedRulesPHPRuleSet(php関連)
- AWSManagedRulesSQLiRuleSet(SQL関連)
- AWSManagedRulesWordPressRuleSet(WordPress特有)
- AWSManagedRulesCommonRuleSet(一般的なwebアプリケーションで有効なルール)
またAWSManagedRulesCommonRuleSetとAWSManagedRulesAnonymousIpListのルールは不正なbotなどに効果がありますので入れておくのが良いかと思います。
最後に
当たり前の話ではありますが実際の運用時には必ず事前に検証を行うようにお願いいたします。入れておくだけで安心感も増しますので、AWS WAFを利用して安全安心なWordPressライフをお楽しみください。