不正アクセスを防ぐためのパーミッション設定 | EC-CUBEユーザーグループ合同勉強会

# 今回は文字が多いので Qiita スライドモードでお送りします

----

## 自己紹介

- 名前: 大河内健太郎(@nanasess) 年齢: 43才
- 出身: 愛知県西尾市一色町
- 在住: 大阪市(四天王寺の近く)
- 前職:寿司屋の板前
- 資格: 調理師・ふぐ処理師
- EC-CUBE コミッター・公式エバンジェリスト
- 最近のマイブーム: [#おうち寿司](https://twitter.com/nanasess/status/1247567924635680770)

----

# [EC-CUBE セキュリティチェックリスト](https://qiita.com/nanasess/items/91209dacdd505c80e2f6) のパーミッション設定を、もう少し深堀りします

----

## EC-CUBEにおける不正アクセスの原因の多く

- 見えちゃいけないファイルが見えていた
- 他の CMS や CGI の脆弱性攻撃
- OSコマンドインジェクション
- SQLインジェクション

*当社調べ*

----

## 見えちゃいけないファイルからの攻撃方法

1. 見えちゃいけないファイルから、セッション奪取
2. 管理画面からテンプレート改竄
3. 購入確認画面に攻撃用 JavaScript を混入
4. [偽の決済画面](https://www.itmedia.co.jp/news/articles/1912/09/news078.html) からカード番号奪取

*あくまでも推測です*

----

## 他の CMS や フリーCGI の脆弱性攻撃

1. 他の CMS や フリーCGIの脆弱性を利用して、 書き込み可能なディレクトリに **攻撃用ファイルを書き込む**
2. 攻撃用ファイルからテンプレート改竄
3. 購入確認画面に攻撃用 JavaScript を混入
4. [偽の決済画面](https://www.itmedia.co.jp/news/articles/1912/09/news078.html) からカード番号奪取

*あくまでも推測です*

----

## OSコマンドインジェクション

1. OSコマンドインジェクションを利用して、 書き込み可能なディレクトリに **攻撃用ファイルを書き込む**
2. 攻撃用ファイルからテンプレート改竄
3. 購入確認画面に攻撃用 JavaScript を混入
4. [偽の決済画面](https://www.itmedia.co.jp/news/articles/1912/09/news078.html) からカード番号奪取

*あくまでも推測です*

----

## SQLインジェクション

1. SQLインジェクションを利用して、データベースに保存されている情報を盗む
 
*数年前から多く悪用されており、カスタマイズ時には注意が必要。[判例あり](https://blog.tokumaru.org/2015/01/sql.html)*

phpMyAdmin や phpPgAdmin を同居させないのも重要

----

## ファイル改竄の直接原因

- Webサーバーのユーザー権限でファイルを書き込まれた
- テンプレートを改竄された

----

## ファイル改竄を防ぐには

- **Webサーバーのユーザー権限で、テンプレートを変更させないこと**
- **Webサーバーのユーザー権限で、書き込める範囲を最小限にすること**

----

## Webサーバーのユーザー権限で、テンプレートを変更させないために

- デザイン管理画面は閉じる
- テンプレートの変更は、 FTP/SSH ユーザー権限で行う
- テンプレートのパーミッションは 604(環境によって変わります)

*多くの共有レンタルサーバーでは FTP/SSH ユーザー権限で Webサーバーが動作しているため、対策できない*

----

## Webサーバーのユーザー権限で、書き込める範囲を最小限にするには

Webサーバーの権限で書き込める箇所は、以下に限定する

- 画像フォルダ(html/upload/save_image)
- キャッシュフォルダ(4系: var, 3系: app/cache, 2系: data/cache, data/Smarty/templates_c)

**プラグインのインストール等、管理画面機能の一部は動作しなくなるが、安全性を高めるためには利便性を削るしかない**

CMS 機能は、 WordPress や Concrete5 などの他の優秀な CMS に任せた方が安全

----

## 他に注意すべきこと

- PHPはデフォルトの設定でファイルやディレクトリを生成した時点では、すべてのユーザーが書き込める状態なので注意(ファイル:666, ディレクトリ:777 になってしまう)
- 定期的にパーミッションをチェックし、変更してあげましょう

```
## 666 のファイルを検索
find . -type f -perm 666

## 604 に変更
find . -type f -perm 666 -print0 | xargs -0 chmod 604

## 777 のディレクトリを検索
find . -type d -perm 777

## 705 に変更
find . -type d -perm 777 -print0 | xargs -0 chmod 705
```

----

## そのほか

- .htaccess を改竄されるケースもある
- 画像ファイルに偽装したバックドアを設置されるケースもある
- .env も見られないように注意
- Nginx など .htaccess の効かない環境は注意
- [WordPress の安全性を高める](https://wpdocs.osdn.jp/WordPress_の安全性を高める)記事は、とても参考になります

----

## まとめ

- 見えちゃいけないファイルは確実に隠そう
- Webサーバーの書き込み権限は最小限に
- 利便性と安全性はトレードオフ。管理画面の機能を限定することも選択肢に

----

# ご静聴ありがとうございました！

----

## 2020-04-10追記

### 管理画面からのデザイン管理を外す方法について

ちなみに、 WordPress は FTP 権限でファイルを更新可能な CMS なので、EC-CUBEより堅牢な実装になっています。
EC-CUBE も、 FTP 権限でデザイン管理画面を更新できるようになれば、もっと安心して使えるようになります。

#### 2系

- `html/<管理画面ディレクトリ>/design` 以下を削除する
- `data/Smarty/templates/admin/main_frame.tpl` から **デザイン管理** のメニューを削除する

#### 3系

- `src/Eccube/ControllerProvider/AdminControllerProvider.php` の137行目付近から149行目付近までをコメントアウト 

```diff
diff --git a/src/Eccube/ControllerProvider/AdminControllerProvider.php b/src/Eccube/ControllerProvider/AdminControllerProvider.php
index b706b6be8..a77adff0a 100644
--- a/src/Eccube/ControllerProvider/AdminControllerProvider.php
+++ b/src/Eccube/ControllerProvider/AdminControllerProvider.php
@@ -134,19 +134,19 @@ class AdminControllerProvider implements ControllerProviderInterface
         $c->match('/content/file_download', '\Eccube\Controller\Admin\Content\FileController::download')->bind('admin_content_file_download');
         $c->delete('/content/file_delete', '\Eccube\Controller\Admin\Content\FileController::delete')->bind('admin_content_file_delete');

-        $c->match('/content/layout', '\Eccube\Controller\Admin\Content\LayoutController::index')->bind('admin_content_layout');
-        $c->match('/content/layout/{id}/edit', '\Eccube\Controller\Admin\Content\LayoutController::index')->assert('id', '\d+')->bind('admin_content_layout_edit');
-        $c->match('/content/layout/{id}/preview', '\Eccube\Controller\Admin\Content\LayoutController::preview')->assert('id', '\d+')->bind('admin_content_layout_preview');
-
-        $c->match('/content/block', '\Eccube\Controller\Admin\Content\BlockController::index')->bind('admin_content_block');
-        $c->match('/content/block/new', '\Eccube\Controller\Admin\Content\BlockController::edit')->bind('admin_content_block_new');
-        $c->match('/content/block/{id}/edit', '\Eccube\Controller\Admin\Content\BlockController::edit')->assert('id', '\d+')->bind('admin_content_block_edit');
-        $c->delete('/content/block/{id}/delete', '\Eccube\Controller\Admin\Content\BlockController::delete')->assert('id', '\d+')->bind('admin_content_block_delete');
-
-        $c->match('/content/page', '\Eccube\Controller\Admin\Content\PageController::index')->bind('admin_content_page');
-        $c->match('/content/page/new', '\Eccube\Controller\Admin\Content\PageController::edit')->bind('admin_content_page_new');
-        $c->match('/content/page/{id}/edit', '\Eccube\Controller\Admin\Content\PageController::edit')->assert('id', '\d+')->bind('admin_content_page_edit');
-        $c->delete('/content/page/{id}/delete', '\Eccube\Controller\Admin\Content\PageController::delete')->assert('id', '\d+')->bind('admin_content_page_delete');
+        // $c->match('/content/layout', '\Eccube\Controller\Admin\Content\LayoutController::index')->bind('admin_content_layout');
+        // $c->match('/content/layout/{id}/edit', '\Eccube\Controller\Admin\Content\LayoutController::index')->assert('id', '\d+')->bind('admin_content_layout_edit');
+        // $c->match('/content/layout/{id}/preview', '\Eccube\Controller\Admin\Content\LayoutController::preview')->assert('id', '\d+')->bind('admin_content_layout_preview');
+
+        // $c->match('/content/block', '\Eccube\Controller\Admin\Content\BlockController::index')->bind('admin_content_block');
+        // $c->match('/content/block/new', '\Eccube\Controller\Admin\Content\BlockController::edit')->bind('admin_content_block_new');
+        // $c->match('/content/block/{id}/edit', '\Eccube\Controller\Admin\Content\BlockController::edit')->assert('id', '\d+')->bind('admin_content_block_edit');
+        // $c->delete('/content/block/{id}/delete', '\Eccube\Controller\Admin\Content\BlockController::delete')->assert('id', '\d+')->bind('admin_content_block_delete');
+
+        // $c->match('/content/page', '\Eccube\Controller\Admin\Content\PageController::index')->bind('admin_content_page');
+        // $c->match('/content/page/new', '\Eccube\Controller\Admin\Content\PageController::edit')->bind('admin_content_page_new');
+        // $c->match('/content/page/{id}/edit', '\Eccube\Controller\Admin\Content\PageController::edit')->assert('id', '\d+')->bind('admin_content_page_edit');
+        // $c->delete('/content/page/{id}/delete', '\Eccube\Controller\Admin\Content\PageController::delete')->assert('id', '\d+')->bind('admin_content_page_delete');

         $c->match('/content/cache', '\Eccube\Controller\Admin\Content\CacheController::index')->bind('admin_content_cache');
```

- `src/Eccube/Resource/config/nav.yml.dist` の58行目付近から63行目付近までをコメントアウト
   - `app/config/eccube/nav.yml` が存在する方は、 同様に58行目付近から63行目付近までをコメントアウト

```diff
diff --git a/src/Eccube/Resource/config/nav.yml.dist b/src/Eccube/Resource/config/nav.yml.dist
index 32662a2a1..a1b5b29ba 100644
--- a/src/Eccube/Resource/config/nav.yml.dist
+++ b/src/Eccube/Resource/config/nav.yml.dist
@@ -55,12 +55,12 @@
       - id: file
         name: ファイル管理
         url: admin_content_file
-      - id: page
-        name: ページ管理
-        url: admin_content_page
-      - id: block
-        name: ブロック管理
-        url: admin_content_block
+      # - id: page
+      #   name: ページ管理
+      #   url: admin_content_page
+      # - id: block
+      #   name: ブロック管理
+      #   url: admin_content_block
       - id: cache
         name: キャッシュ管理
         url: admin_content_cache
```

#### 4系

- `app/config/eccube/packages/eccube_nav.yaml` の61行目付近から66行目付近と、73行目付近から75行目付近をコメントアウト

```diff
diff --git a/app/config/eccube/packages/eccube_nav.yaml b/app/config/eccube/packages/eccube_nav.yaml
index 5abb0b706f..d99603c01a 100644
--- a/app/config/eccube/packages/eccube_nav.yaml
+++ b/app/config/eccube/packages/eccube_nav.yaml
@@ -58,21 +58,21 @@ parameters:
                 file:
                     name: admin.content.file_management
                     url: admin_content_file
-                layout:
-                    name: admin.content.layout_management
-                    url: admin_content_layout
-                page:
-                    name: admin.content.page_management
-                    url: admin_content_page
+                # layout:
+                #     name: admin.content.layout_management
+                #     url: admin_content_layout
+                # page:
+                #     name: admin.content.page_management
+                #     url: admin_content_page
                 css:
                     name: admin.content.css_management
                     url: admin_content_css
                 js:
                     name: admin.content.js_management
                     url: admin_content_js
-                block:
-                    name: admin.content.block_management
-                    url: admin_content_block
+                # block:
+                #     name: admin.content.block_management
+                #     url: admin_content_block
                 cache:
                     name: admin.content.cache_management
                     url: admin_content_cache
```

- 以下の Controller の `@Route` を `//@Route` に変更
   - `src/Eccube/Controller/Admin/Content/BlockController.php`
   - `src/Eccube/Controller/Admin/Content/LayoutController.php`
   - `src/Eccube/Controller/Admin/Content/PageController.php`
   - 

```diff
diff --git a/src/Eccube/Controller/Admin/Content/BlockController.php b/src/Eccube/Controller/Admin/Content/BlockController.php
index ce78ae3a65..d5a0501536 100644
--- a/src/Eccube/Controller/Admin/Content/BlockController.php
+++ b/src/Eccube/Controller/Admin/Content/BlockController.php
@@ -51,7 +51,7 @@ class BlockController extends AbstractController
     }
 
     /**
-     * @Route("/%eccube_admin_route%/content/block", name="admin_content_block")
+     * //@Route("/%eccube_admin_route%/content/block", name="admin_content_block")
      * @Template("@admin/Content/block.twig")
      */
     public function index(Request $request)
@@ -77,8 +77,8 @@ class BlockController extends AbstractController
     }
 
     /**
-     * @Route("/%eccube_admin_route%/content/block/new", name="admin_content_block_new")
-     * @Route("/%eccube_admin_route%/content/block/{id}/edit", requirements={"id" = "\d+"}, name="admin_content_block_edit")
+     * //@Route("/%eccube_admin_route%/content/block/new", name="admin_content_block_new")
+     * //@Route("/%eccube_admin_route%/content/block/{id}/edit", requirements={"id" = "\d+"}, name="admin_content_block_edit")
      * @Template("@admin/Content/block_edit.twig")
      */
     public function edit(Request $request, $id = null, Environment $twig, FileSystem $fs, CacheUtil $cacheUtil)
@@ -180,7 +180,7 @@ class BlockController extends AbstractController
     }
 
     /**
-     * @Route("/%eccube_admin_route%/content/block/{id}/delete", requirements={"id" = "\d+"}, name="admin_content_block_delete", methods={"DELETE"})
+     * //@Route("/%eccube_admin_route%/content/block/{id}/delete", requirements={"id" = "\d+"}, name="admin_content_block_delete", methods={"DELETE"})
      */
     public function delete(Request $request, Block $Block, Filesystem $fs, CacheUtil $cacheUtil)
     {
diff --git a/src/Eccube/Controller/Admin/Content/LayoutController.php b/src/Eccube/Controller/Admin/Content/LayoutController.php
index eddbb86f12..5b6c764096 100644
--- a/src/Eccube/Controller/Admin/Content/LayoutController.php
+++ b/src/Eccube/Controller/Admin/Content/LayoutController.php
@@ -100,7 +100,7 @@ class LayoutController extends AbstractController
     }
 
     /**
-     * @Route("/%eccube_admin_route%/content/layout", name="admin_content_layout")
+     * //@Route("/%eccube_admin_route%/content/layout", name="admin_content_layout")
      * @Template("@admin/Content/layout_list.twig")
      */
     public function index()
@@ -119,7 +119,7 @@ class LayoutController extends AbstractController
     }
 
     /**
-     * @Route("/%eccube_admin_route%/content/layout/{id}/delete", requirements={"id" = "\d+"}, name="admin_content_layout_delete", methods={"DELETE"})
+     * //@Route("/%eccube_admin_route%/content/layout/{id}/delete", requirements={"id" = "\d+"}, name="admin_content_layout_delete", methods={"DELETE"})
      *
      * @param Layout $Layout
      *
@@ -148,8 +148,8 @@ class LayoutController extends AbstractController
     }
 
     /**
-     * @Route("/%eccube_admin_route%/content/layout/new", name="admin_content_layout_new")
-     * @Route("/%eccube_admin_route%/content/layout/{id}/edit", requirements={"id" = "\d+"}, name="admin_content_layout_edit")
+     * //@Route("/%eccube_admin_route%/content/layout/new", name="admin_content_layout_new")
+     * //@Route("/%eccube_admin_route%/content/layout/{id}/edit", requirements={"id" = "\d+"}, name="admin_content_layout_edit")
      * @Template("@admin/Content/layout.twig")
      */
     public function edit(Request $request, $id = null, $previewPageId = null, CacheUtil $cacheUtil)
@@ -236,7 +236,7 @@ class LayoutController extends AbstractController
     }
 
     /**
-     * @Route("/%eccube_admin_route%/content/layout/view_block", name="admin_content_layout_view_block", methods={"GET"})
+     * //@Route("/%eccube_admin_route%/content/layout/view_block", name="admin_content_layout_view_block", methods={"GET"})
      *
      * @param Request $request
      * @param Twig $twig
@@ -272,7 +272,7 @@ class LayoutController extends AbstractController
     }
 
     /**
-     * @Route("/%eccube_admin_route%/content/layout/{id}/preview", requirements={"id" = "\d+"}, name="admin_content_layout_preview")
+     * //@Route("/%eccube_admin_route%/content/layout/{id}/preview", requirements={"id" = "\d+"}, name="admin_content_layout_preview")
      */
     public function preview(Request $request, $id, CacheUtil $cacheUtil)
     {
diff --git a/src/Eccube/Controller/Admin/Content/PageController.php b/src/Eccube/Controller/Admin/Content/PageController.php
index 13bf8cfe0f..2d8d0e8a07 100644
--- a/src/Eccube/Controller/Admin/Content/PageController.php
+++ b/src/Eccube/Controller/Admin/Content/PageController.php
@@ -65,7 +65,7 @@ class PageController extends AbstractController
     }
 
     /**
-     * @Route("/%eccube_admin_route%/content/page", name="admin_content_page")
+     * //@Route("/%eccube_admin_route%/content/page", name="admin_content_page")
      * @Template("@admin/Content/page.twig")
      */
     public function index(Request $request)
@@ -86,8 +86,8 @@ class PageController extends AbstractController
     }
 
     /**
-     * @Route("/%eccube_admin_route%/content/page/new", name="admin_content_page_new")
-     * @Route("/%eccube_admin_route%/content/page/{id}/edit", requirements={"id" = "\d+"}, name="admin_content_page_edit")
+     * //@Route("/%eccube_admin_route%/content/page/new", name="admin_content_page_new")
+     * //@Route("/%eccube_admin_route%/content/page/{id}/edit", requirements={"id" = "\d+"}, name="admin_content_page_edit")
      * @Template("@admin/Content/page_edit.twig")
      */
     public function edit(Request $request, $id = null, Environment $twig, RouterInterface $router, CacheUtil $cacheUtil)
@@ -250,7 +250,7 @@ class PageController extends AbstractController
     }
 
     /**
-     * @Route("/%eccube_admin_route%/content/page/{id}/delete", requirements={"id" = "\d+"}, name="admin_content_page_delete", methods={"DELETE"})
+     * //@Route("/%eccube_admin_route%/content/page/{id}/delete", requirements={"id" = "\d+"}, name="admin_content_page_delete", methods={"DELETE"})
      */
     public function delete(Request $request, $id = null, CacheUtil $cacheUtil)
     {
```