WordPress для параноїків, частина 1

Отже, якщо ви щасливий власник nginx, знатний параноїк і за якимось чортом вирішили поставити wordpress, то… Перше, що спало на думку — це «треба обмежити цьому творінню свободу!».

Налаштування облікового запису, як і налаштування php5-fpm, я опущу, тому що у кожного свої таргани, а хтось взагалі на apache запускає. Але загальні для Wordpress я опишу в цій частині. Напишу про те, що зробив, що сталося і чому.

Що ж нам потрібне? Нам потрібно обмежити доступ до php файлів та адмінки, винести статику, закрити xmlrpc.

Обмежуємо доступ до адмінки та до php файлів

Після цього при запитах xmlrpc.php та .htaccess ми матимемо 404 помилки. Хоча можна видати і 403 і 200 «trololo», але це вже справа смаку.

Далі обмежуємо доступ до файлів:

Запис виду /wp-includes/.*?\.php включає всіphp файли в wp-includes і нижче.

Готово доступ ми закрили. Тепер вибірково включатимемо потрібні нам елементи для паблік версії, а це далі за текстом.

Включаємо захищені записи у нашому захищеному Wordpress

Слідом у конфізі nginx прописуємо:

У такому разі при запиті/wp-postpass.php?action=postpass змінна wppostpass прийме значення 1, і location відпрацює до кінця. У разі голого запитуwp-postpass.php або з іншими параметрами (як бачить, що тут перевіряється від початку ^ до кінця$ рядка) буде помилка 403, що означає доступ закритий.

Для роботи такої схеми нам потрібний ngx_http_substitutions_filter_module. У конфізі слід прописати

Виносимо статику на окремий сервер та підключаємо CDN

У навантаженні js, css і дрібні gif'ки ролі не грають, тому що за наявності пам'яті nginx зберігає їх у своєму кеші, а за наявності достатньої кількості пам'яті всю статику сайтуможна винести на розділ tmpfs (3.8 Гб читання-запис і 745к iops'ів наприклад).

Але в разі одного сервера хтось отримає файл раніше, хтось пізніше, і якщо у нас багато клієнтів, то при роздачі 1000 файлів по 1Мб канал нехило просяде, якщо не вводити rate.

Ось для цих випадків і придумані провайдери, що кешують CDN. Для прикладу - cloudflare.

Принцип робота чудово проілюстрований на їхній картинці:

параноїків

Без CDN всі запити йдуть на кінцевий сайт, а з CDN запити йдуть на провайдера CDN, який виступає як проміжна ланка. І в цьому випадку якщо 1000 користувачів запросять файл розмірів 1 Мб, то цей файл буде запитаний CDN провайдером 1 раз для свого кеша, а потім роздано 1000 користувачів. Варіанти DDoS'а в стилі a la google docs, коли запросили big_photo.jpg?ver=1, потім big_photo.jpg?ver=2, і т.д. не спрацює, якщо вибрано режимпомірного кешування (у cloudflare він є) і кешування тільки статики, то при запитіbig_photo.jpg,big_photo.jpg?ver=1 абоbig_photo.jpg?ver=123 з сервера запитуєтьсяbig_photo.jpg і потім лунає він і тільки він, навіть якщо клієнт запитує файл з аргументами (вони просто ігноруються). Це вирішує проблему ддоса cdn провайдером, який, по суті, повинен і від ддоса захищати.

Я не сильно лазив, але виявив, що дефолтова статика зберігається в:

  • /wp-content/uploads/
  • /wp-content/themes/
  • /wp-content/plugins/
  • /wp-includes/js/
  • /wp-includes/css/
  • /wp-includes/certificates/
  • /wp-includes/fonts/
  • /wp-includes/images/
Відповідно для них ми і зробимо нові правила в location і будемо використовувати nginx c ngx_http_substitutions_filter_module. Ставити цей модуль необов'язково, можна обійтися одними лише rewrite'ами, але сам по собі він корисний і через нього можна покращити той чи інший висновок з backend'а.

До конфіг додаємо:

Щоб фільтрувати виведення html та xml документів.

Таким чином, посилання в html і xml будуть переписані. Тепер залишилося зробити так, щоб кінцевий користувач, знаючи оригінальне посилання, не абузив сервер, а спрямований на CDN.

У результаті при запиті будь-якого php файлу нічого не буде. А при запиті статики (все, що не php у випадку з WP, що логічно) користувач буде перенаправлений на сервер статики.

Налаштування профілю nginx для сервера статики буде розглянуто нижче.

Налаштування сервера статики

Оскільки ми перенесли віддачу на сервер статики, необхідно його правильно налаштувати.

Потрібно дозволити доступ локалхосту, доступ серверу із зовнішнього IP (наприклад який скрипт) і серверам CDN провайдера. Наприклад, підмережі CloudFlare можна знайти ось за цим посиланням. І, звичайно, закрити доступ всім іншим. Оскільки CDN раптово вирішить пустити трафік на пряму… залишити вільний канал.

Так само треба зробити dummy директорію як root для всього сервера статики.

Щоб запити, які прийшли на сервер статики наlocation / або=/ і які не відповідають прописаним там location пішли в ту самуdummy директорію. Ця директорія прописується всерединіserver<>.

Далі location привітання:

Це текст, який побачить користувач, котрий запросив корінь. Писати можна будь-що, головне при використанні всередині" екранувати лапки як\".

Потім слід прописатиlocation 'и на статику:

За запитомstatic.example.com/images/pic.png сервер віддасть файл з директорії/wp-includes/images/ файлpic.png, але при запитіstatic.example.com/images/pic.php location клацає і в результаті користувачеві віддадуть файл з dummy/images/pic.php, якого немає і як наслідок помилка 404.

Ще треба додати рейти на швидкість.

Після 16 мегабайт швидкість зменшується до 2 Мб на секундуна потік. Це щоб CDN при кешуванні величезного файлу не забив весь канал.

У випадку з cloudflare максимальний розмір файлу (на момент написання цього матеріалу) становить 512 мегабайт, а формати, що підтримуються, на безкоштовному тарифному плані включають: css, js, jpg, jpeg, gif, ico, png, bmp, pict, csv, doc, pdf , pls, ppt, tif, tiff, eps, ejs, swf, midi, mid, ttf, eot, woff, otf, svg, svgz, webp, docx, xlsx, xls, pptx, ps, class, jar.

Фільтрування запитів

Тоді якщо в аргументах запиту зустрінуться attachment_id, eval, duplicate, base64, substring, preg_replace, create_function nginx поверне помилку 403, причому запит не буде передано на динаміку виконання потенційної вразливості.

Плюшки через subs_filter від nginx

Призначення цього модуля розглянуто тут.

Завдання: wordpress за промовчанням відкриває посилання на медіафайл у поточному вікні. А треба, щоб у новому.

Рішення: додати невеликий код в когфіг nginx.

Завдання: всюди xmlrpc.php посилання… треба прибрати.

Рішення: додати невеликий код в когфіг nginx.

А в xmlrpc.txt можна засунути пасхалочку.

Післямова

А у нас тут можна отримати грант на тестовий період Яндекс.Хмари. Варто лише у полі «секретний пароль» запровадити «Хабр»