تتعرض منصة Discourse الخاصة بـ freeCodeCamp.org للانهيار بسبب نصوص برمجية للمحتالين

We started seeing heightened loads on the freeCodeCamp.org Discourse on June 21. Our average CPU load started to grow to the point that the entire forum became unresponsive.

Our Initial investigation

  1. We updated Discourse from the Stable version to the latest Tests-Passed (Beta) version, which is recommended to get all the latest performance fixes. There seemed to not be much of a difference.

  2. We got rid of some of the old plugins to help diagnose the issue, and it does not seem to be the case for slow down.

  3. To rule out any misconfigurations, we tested this with the default theme and checked the /logs and did find some exceptions:

    Job exception: could not obtain connection from the pool within 5.000 seconds (awaited 5.006 seconds); all pooled connections were in use

This seems to be because the instance may already stressed out with a lot of long running jobs.

The discourse container (upstream) is running on Digital Ocean, and seems to be running hot on all 6 vCPUs. It is currently running on version: 2.5.0.beta7

Further investigation

  1. This morning our moderators let us know that there was a significant increase in the number of spam accounts, which was leading us to believe that this could be a targeted attack.

  2. To try and mitigate the issue, we have put the forum into read-only mode. Despite this, the resource utilization rate remains quite high at 60+%.

  3. From what we can tell: ever since this started, we have been seeing a lower requests-per-second and higher current request rate on our proxy:

  1. The volume of traffic to freecodecamp.org/forum has not significantly changed according to Google Analytics.
  2. None of the other applications on the same proxy seem to be affected. Our /news and /learn platform are operating normally.
  3. We tried adding some additional rate limiting on the proxy, and it did not make much difference, so we removed it (to allow normal users to continue to reach our site).
  4. We have also moved our old forum.freecodecamp.com redirects away from the .org forum since we noticed that old subdomain (which we haven’t used in 2.5 years) had a big spike in traffic starting a few days ago.

At the moment with ~400 real-time users, the stats look like so:

Observations About The Spammer’s Behavior

The spammers seem to be running some sort of script that creates new accounts on a Discourse instance, then waits several days. Then those accounts suddenly become active. They start posting new threads with links to a website. (Perhaps to build backlinks?)

Some of these accounts were created all the way back in March.

Here’s what one of their spam posts look like, though there are a lot of variants, linking to a lot of websites:

Any advice would be welcome here.

14 إعجابًا

This deserves much more attention

Thank you so much for sharing!

One of my favorite Discourse instances, freeCodeCamp, has slowed to a halt the last two days.

5 إعجابات

I don’t think that the heavy load main problem caused by spammer.
Here is why:

Normal discourse usage (without API) can only work with modern browser because it heavily depend on javascript. Google Analytics use javascript too to collect various user informations (and doesn’t need modern javascript support to run the analytics code). If Google Analytics can’t detect user activity, then discourse should not be able to serve its content and features.

Here is bot capture when I use old headless browser library (phantomjs) to access discourse site :

And here is with more modern library (puppeteer)

  1. It’s just strange if someone able to post (without API) replies on discourse while google analytics can’t detect them.
  2. Usually, spammers use public proxy to do dirty things and I think your cloudflare is smart enough to stop “bad visitors” before really reach your app.

Did you see high queue jobs on sidekiq process?

إعجابَين (2)

This ignores the fact that more than half of people in tech communities are running some sort of Ad Block extension, which always block Google Analytics by default.

18 إعجابًا

Including the new macOS.

Was nasty rumour only. See below.

5 إعجابات

Is akismet enabled? Can you turn on moderation for trust level 1?

إعجابَين (2)

Yes, we did see the jobs kicking up and down as a part of my initial investigation. We then proceeded to revoke all of the user keys.

It does not seem have had done any change on the stability though.

Although we are working very closely with the Discourse team to resolve this.

5 إعجابات

I don’t see why it’s strange if there can be requests without js based analytics showing anything.
The spammer can use the same endpoints as the javascript does, without javascript. No javascript based analytics would trigger

3 إعجابات

This is far more likely to be a plug-in interaction or bad proxying config. We see zero success from “spammers” on our hosting.

Given it is a coding site it could also be “coders” trying to do something weird on the forum as well?

But no — spammers aren’t a generalized problem across the thousands of sites we host.

3 إعجابات

Yes, I am inclined its either config (bad plugin or proxing setup) or someone messing with forum.

The later is more probable cause from all the patterns.

From what I have noticed is that the spam accounts have been created over a long period of time and there are trying to add links (to gain backlinks??) in their bios and all sorts of weirdness.

Also, there could be scraping involved because we have put the site in read-only and have a cache setup on the proxy too along with rate limiting. The resource usage seems to be high regardless on the upstream container.

However, I would not rule out our config could be bad as well, we use subpaths and Cloudflare on top of our reverse proxy which traditionally is not the most efficient setup that Discourse recommends.

إعجاب واحد (1)

image

42.5% steal is really high, even if you’re the one that is causing the issues on that hypervisor. This looks like a noisy neighbour to me. If I were you I would contact DO and ask them to move the droplet to another hypervisor.

10 إعجابات

I’m sure you probably doing that but just to be sure I’d suggest monitoring open tcp / udp connections summarized by IP on OS level. If there is high CPU load it should show you massive amount of open connections to the webserver.

Any strange pattern in production.log?

إعجاب واحد (1)
4 إعجابات

مرحبًا كوينسي @ossia

دعنا نأخذ خطوة سريعة للخلف للحظة وننظر إلى هذا من منظور أمني سيبراني احترافي، دون التكهنات أو نهج “التمسك بالقش”.

المفهوم الرئيسي في جميع مهام الأمن السيبراني هو مفهوم “الوعي الظرفي”، لذا في هذه الحالة يُسمى “الوعي الظرفي السيبراني” (CSA).

ولمعرفة “ما يحدث” بشكل قاطع، تحتاج إلى تطوير أفضل معرفة ظرفية ممكنة دون تكهنات أو تخمين. فقط الحقائق.

كيف تفعل ذلك؟

حسنًا، باختصار شديد:

حسنًا، باختصار شديد:

نقوم بذلك من خلال دمج المعلومات من جميع أجهزة الاستشعار لدينا، وبالنسبة للتطبيقات القائمة على الويب، تأتي هذه المعلومات عادةً من ملفات السجل (log files) وبيانات الجلسة. لا أعتقد (بناءً على ما أعرفه فورًا) أن نظام discourse يحفظ معلومات الجلسة في قاعدة بيانات PG (آخر مرة تفحصت فيها لم يكن هناك جدول للجلسات مثل بعض تطبيقات الويب LAMP)، لكن هذا ليس عائقًا على الإطلاق.

لديك معظم ما تحتاجه في ملفات سجل nginx لكل من وكيل العكس (reverse proxy) الموجود خارج الحاوية (أتذكر أنني قرأت في هذا الموضوع أنك تستخدم nginx كوكيل)، ومعلومات السجل نفسها موجودة أيضًا داخل الحاوية. في كلتا الحالتين، يقع ملف السجل هنا، في الإعداد القياسي OOTB:

إليك مثالًا في أحد إعداداتنا (خارج الحاوية) لوكيل العكس:

# cd /var/log/nginx
# ls -l 
total 779964
-rw-r----- 1 www-data adm         0 Jun 17 06:25 access.log
-rw-r----- 1 www-data adm 660766201 Jun 25 18:26 access.log.1
-rw-r----- 1 www-data adm 107367317 Jun 17 03:18 access.log.2.gz
-rw-r----- 1 www-data adm  21890638 May 21 03:08 access.log.3.gz
-rw-r----- 1 www-data adm   7414232 May  5 07:26 access.log.4.gz
-rw-r----- 1 www-data adm     63289 Apr 18 09:12 access.log.5.gz
-rw-r----- 1 www-data adm         0 Jun 17 06:25 error.log
-rw-r----- 1 www-data adm    904864 Jun 25 18:19 error.log.1
-rw-r----- 1 www-data adm     96255 Jun 17 03:17 error.log.2.gz
-rw-r----- 1 www-data adm     79065 May 21 02:58 error.log.3.gz
-rw-r----- 1 www-data adm     70799 May  5 06:54 error.log.4.gz
-rw-r----- 1 www-data adm      1977 Apr 18 05:49 error.log.5.gz

وإليك نفس معلومات السجل الأساسية داخل حاوية discourse:

# cd /var/discourse/
# ./launcher enter socket
# cd /var/log/nginx
# ls -l
total 215440
-rw-r--r-- 1 www-data www-data  87002396 Jun 25 18:28 access.log
-rw-r--r-- 1 www-data www-data 101014650 Jun 25 08:02 access.log.1
-rw-r--r-- 1 www-data www-data   8217731 Jun 24 08:02 access.log.2.gz
-rw-r--r-- 1 www-data www-data   6972317 Jun 23 07:53 access.log.3.gz
-rw-r--r-- 1 www-data www-data   3136381 Jun 22 07:50 access.log.4.gz
-rw-r--r-- 1 www-data www-data   2661418 Jun 21 07:45 access.log.5.gz
-rw-r--r-- 1 www-data www-data   5098097 Jun 20 07:38 access.log.6.gz
-rw-r--r-- 1 www-data www-data   6461672 Jun 19 07:40 access.log.7.gz
-rw-r--r-- 1 www-data www-data         0 Jun 25 08:02 error.log
-rw-r--r-- 1 www-data www-data         0 Jun 24 08:02 error.log.1
-rw-r--r-- 1 www-data www-data        20 Jun 23 07:53 error.log.2.gz
-rw-r--r-- 1 www-data www-data       254 Jun 23 02:36 error.log.3.gz
-rw-r--r-- 1 www-data www-data        20 Jun 21 07:45 error.log.4.gz
-rw-r--r-- 1 www-data www-data        20 Jun 20 07:38 error.log.5.gz
-rw-r--r-- 1 www-data www-data        20 Jun 19 07:40 error.log.6.gz
-rw-r--r-- 1 www-data www-data       274 Jun 18 15:40 error.log.7.gz

ملاحظة: هذه المعلومات “داخل الحاوية” متاحة أيضًا من خارج الحاوية على الحجم المشترك (shared volume).

وبالتالي (ولإبقاء هذه الإجابة قصيرة)، @ossia، فكل ما تحتاجه تقريبًا لاكتساب معرفة ظرفية لما يحدث موجود في ملفات السجل هذه القوية. لا حاجة للتكهنات. البيانات موجودة جميعها.

هناك حتى بيانات رائعة أخرى متاحة في سجل rails، على سبيل المثال. في أحد إعداداتنا هنا، إليك سجل الإنتاج rails:

tail -f /var/discourse/shared/socket/log/rails/production.log

يحتوي سجل rails على الكثير من معلومات تسجيل الدخول الرائعة للمستخدمين أيضًا، على سبيل المثال:

Started GET "/embed/comments?topic_id=378686" for 73.63.114.60 at 2020-06-25 18:36:15 +0000
Started GET "/embed/comments?topic_id=378686" for 195.184.106.202 at 2020-06-25 18:36:16 +0000
Started GET "/embed/comments?topic_id=378686" for 17.150.212.174 at 2020-06-25 18:36:16 +0000
Started GET "/embed/comments?topic_id=378686" for 76.235.99.73 at 2020-06-25 18:36:18 +0000
Started GET "/embed/comments?topic_id=378686" for 124.253.211.42 at 2020-06-25 18:36:19 +0000
Started GET "/embed/comments?topic_id=378686" for 103.96.30.11 at 2020-06-25 18:36:21 +0000
Started GET "/embed/comments?topic_id=378686" for 72.191.206.59 at 2020-06-25 18:36:22 +0000
Started GET "/embed/comments?topic_id=378686" for 68.252.68.76 at 2020-06-25 18:36:23 +0000
Started GET "/embed/comments?topic_id=378686" for 69.17.252.83 at 2020-06-25 18:36:23 +0000
Started GET "/embed/comments?topic_id=378686" for 98.109.33.230 at 2020-06-25 18:36:24 +0000

ملاحظة: هنا (أعلى، كمثال) نرى عناوين IP للعملاء الذين يسحبون كود التضمين (embedded code) الخاص بـ discourse من خادم آخر.

المهمة المطروحة....

نعود إلى المهمة المطروحة، “الحيلة” هي تجاوز التكهنات والتخمين، والقيام بالمرحلتين الممتعتين: (1) التصفية/تنظيف البيانات، (2) دمج البيانات، و (3) تحليل بيانات أجهزة الاستشعار لديك (ملفات السجل) لإنشاء (4) الوعي الظرفي (SA) لما يحدث في موقعك.

بالنسبة لتطبيقات LAMP الأقدم، لدي في الواقع كود مخصص كتبته منذ سنوات يقوم بكتابة كل هذه المعلومات إلى جدول قاعدة بيانات ويقوم بالتحليل في الوقت الفعلي ويحسب “النقرات” حسب عنوان IP (كمثال واحد) حيث يمكنني رؤية ما يحدث ومن ومن أين يضرب الموقع بسرعة، لأن هذا النوع من تنظيف البيانات وتصفيتها ودمجها يتطلب بعض الكود. (مفيد أثناء هجمات DDOS ونشاط الروبوتات الخبيثة، على سبيل المثال).

هذا ليس مشكلة بالنسبة لك @ossia لأنك freeCodeCamp.org، لذا لديك كل من المعرفة للعثور على أدوات رائعة لتحليل ملفات السجل (هناك العديد منها في العالم السيبراني) و/أو إنشاء كود مخصص خاص بك لإجراء التحليل بسرعة وسهولة بناءً على السيناريو الذي ترغب في فهمه (موضوعك ومشكلتك).

لقد كتبت كودي المخصص لتطبيق LAMP قديم قبل سنوات في بضع ساعات، وأنا لست عبقري برمجة بأي حال من الأحوال، حتى لو يُشار إليّ أحيانًا بـ “أسطورة” من قبل العديد في مجال الأمن السيبراني، LOL :slight_smile:

للخلاصة....

حسنًا، للخلاصة…

لديك جميع البيانات التي تحتاجها لإنشاء معرفة ظرفية عميقة حول “ما يحدث” في موقعك. ويمكنك إنشاء هذا الوعي الظرفي (SA) من خلال تنظيف وتصفية ودمج وإجراء بعض التحليلات الأساسية لبيانات ملفات السجل لديك. هناك أدوات متاحة يمكن أن تساعد، لكنني دائمًا ما أجد أنه من الأسهل كتابة بعض الكود المخصص بناءً على هدف التحليل (تحليل معتمد)، وقد يختلف الأمر من شخص لآخر. لكن يمكنك القيام بذلك بسهولة لأنك freeCodeCamp.org ولديك الكثير من المهارات التقنية.

أوصيك بالابتعاد عن محاولة اكتساب الوعي الظرفي (SA) من Google Analytics وتطبيقات الطرف الثالث الأخرى القائمة على JavaScript. لا يوجد شيء أفضل من ملفات سجل الويب الخاصة بك (وأيضًا بيانات جلسة قاعدة البيانات إذا كانت متاحة لديك)، ولا داعي للقلق بشأن “ما قد يتم حظره أو لا” وما إلى ذلك. تحتوي ملفات سجل خادم الويب لديك على البيانات اللازمة لاكتساب الوعي الظرفي السيبراني (CSA) الذي تحتاجه (ويمكن أيضًا تخصيصها عند الحاجة).

في بعض أكواد الوعي الظرفي السيبراني (CSA) الخاصة بي، أقوم فعليًا باعتراض معلومات الجلسة ومعلومات السجل من طلبات HTTP التي لا يسجلها nginx أو apache2 أو خوادم الويب الأخرى (لمعلومات إضافية)؛ لكنني لم أكتب هذا النوع من الكود لـ discourse (بعد) لأنني لست “سهلًا مثل الفطيرة” كمطور إضافات discourse (مثل خبراء فريق meta discourse هنا) كما هو الحال مع تطبيقات LAMP، حيث بدأت فقط مع discourse قبل بضعة أشهر ولم أكتب بعد أي كود مخصص للوعي الظرفي السيبراني (CSA) لـ discourse (وحاولت كتابة كود أقل هذا العام، بصراحة).

الوعي الظرفي السيبراني (CSA) مبني على دمج بيانات أجهزة الاستشعار، ومن الوعي الظرفي السيبراني (CSA) تنبع المعرفة لفهم الإجراءات التي تحتاج إلى اتخاذها لتصحيح أي مشكلة أمنية سيبرانية.

كل التوفيق في سعيك، وآمل أن يساعدك هذا على الحصول على راحة أكثر :slight_smile:

تحياتي!


المرجع الأصلي (التاريخي) للوعي الظرفي السيبراني (CSA):

المرجع الأصلي (التاريخي) للوعي الظرفي السيبراني (CSA):

https://www.researchgate.net/publication/220420389_Intrusion_Detection_Systems_and_Multisensor_Data_Fusion

(مرجع فقط للأشخاص المهتمين بأصول وتقنية الوعي الظرفي السيبراني الأساسية)

13 إعجابًا

شكرًا لكم على عملكم الشاق، يا فريق!

وشكرًا لكم جـدًا جدًا جدًا
على تبسيط
شريط الأدوات المزدوج :nauseated_face:

4 إعجابات

سأقوم فقط بإغلاق الحلقة هنا.

تستضيف منصة Discourse الآن https://forum.freecodecamp.org/. الموقع سريع للغاية، ولم تعد سكريبتات المُرسلين المزعجين تسبب حتى أدنى اضطراب. لا يزال لدينا بعض الغموض حول المشكلة التي كانت موجودة على Digital Ocean؛ فقد يكون هناك جار “صاخب”، أو أن الجهاز كان ضعيف الطاقة، أو ربما كانت هناك أعطال غير مفسرة في الجهاز، ونحن غير متأكدين. لكن المشكلة الأصلية قد حُلت بنسبة 100% الآن، والمجتمع سعيد جداً.

16 إعجابًا