با مسدود شدن تلگرام در روسیه، امروز نسخه ی 4.8.6 فقط برای روسیه منتشر شده است، در این نسخه از تکنیک Domain Fronting یا درست تر آن HTTPS Domain Fronting برای جلوگیری از سانسور پیاده سازی شده است، در این تاپیک به طور کامل طریقه کار این تکنیک را(به صورت ساده)شرح داده و یک پروژه Domain Fronting بروی سرویس Google App Engine با زبان برنامه نویسی پایتون و PHP پیاده سازی می کنیم و در صورتی که دوباره وقت آزادی داشته باشم یک پروژه Domain Fronting بدون نیاز به اسکریپت نویسی Reflector بروی Cloudflare، پیاده سازی می کنیم.
برای پیاده سازی این تکنیک نیاز به سرویس دهنده های شبکه تحویل محتوا (CDN) یا سرویس App Engine گوگل داریم (در صورت استفاده از App Engine نیاز به اسکریپت نویسی برای Reflector داریم)
پیش نیاز ها :
تقریبا هر فعالیتی که شما در اینترنت انجام می دهید با پرس و جوی DNS آغاز می شود، به صورت خلاصه و ساده میتوان گفت یک دفترچه تلفن اینترنت است که که آدرس های IP را به اسامی قابل فهم انسانی مانند myname.com تبدیل می کند، سرویس دهنده های اینترنتبرای سانسور و ..کوئری های DNS مشتریانشان را به سمت DNS سرور های خودشان ارسال میکنند.
Edge Server در CDN :اولین هدف این سرور ها، ذخیره محتوای استاتیک (Image,HTML,CSS,JS File)و نزدیک بودن سرور به کاربر جهت کاهش تاخیر و بالا بردن سرعت لود پیج است.
Origin Server در CDN :این سرور وظیفه پاسخ به درخواست های کاربر را دارد،به صورت خلاصه همان سرور Backend شما است که برای لود محتوا داینامیک و پردازش درخواست ها استفاده می شود.
مثال :
فرض کنید سایتی را میخواهید باز کنید که از سرویس CDN کلود فلار استفاده می کند، صفحه Index.php را باز می کنیم، در این صفحه یک عکس به نام Image.png به همراه یک فرم لاگین وجود دارد، در صورتی که کاربر صفحه را باز کند ابتدا یک درخواست برای بارگذاری عکس Image.png به صورت زیر برای سرور Edge ارسال می شود :
در صورتی که فرم لاگین را تکمیل و ارسال کنیم، لازم است اطلاعات را به سرور Origin ارسال و درستی آن تایید شود سپس پاسخ را به Edge سرور فرستاده تا آن را برای کاربر ارسال کند :
در تکنیک Domain Fronting سرویس دهنده از یک سرویس CDN استفاده کرده و کلاینت درخواست HTTP خود به جای اینکه مستقیم به سرور اصلی ارسال کند به Edge Server ارسال می کند، پس از دید ISP پرس و جوی DNS ما (به طور مثال) Cloudflare است، اما در هیدر HTTP به سرور اصلی اشاره شده است، Edge Server وظیفه دارد محتوای درخواست ما را بخواند و به آدرسی که مشخص شده است درخواست را ارسال کرده و پاسخ را بازگشت دهد (Origin-Pull). به همین سادگی سانسور را دور میزنیم.
در این روش تنها راهی که برای سانسور می ماند، سانسور Edge سرور است، پس برای عملی کردن این روش نیاز به سرویس دهنده ای داریم که پهنای باند زیادی از اینترنت را برای خود کرده باشد و مسدود سازی آن موجب تداخل شود، به طور مثال اگر از Google App Engine برای پیاده سازی Domain Fronting استفاده کنیم، ISP باید پرس و جوی DNS گوگل مسدود کند و این یعنی فاجعه...
مثال ارسال درخواست به سرور Edge :
درخواست ما به forbidden.com ارسال خواهد شد اما پرس و جوی DNS و SNI در هندشیک allowed.com خواهد بود.
کد:
wget -q -O - https://allowed.com --header Host: forbidden.com
#تمام سرویس دهنده ها CDN از تکنیک Origin-Pull استفاده نمی کنند که در این صورت با توجه به امکاناتسرویس دهنده در صورتی که امکانش باشد باید Reflector نوشت تا Edge Server درخواست ما را بازتاب کند به سرور اصلی.
#در صورتی که محتوا یا هیدر درخواست HTTP ما انکریپت شده نباشد ISP قادر به سانسور کردن است، پسTLSدر اینجا به کمک ما آمده و محتوای درخواست ما را انکریپت و کاملا امن خواهد کرد و فقط Edge سرور می تواند آن را بخواند.
#فقط سرویس دهنده CDN از آدرس سرور اصلی اطلاع دارد، در صورتی که ISP به هر طریقی آدرس سرور اصلی را پیدا کند و آن را سانسور کند، اثری نخواهد داشت.
(در عکس بالا کلاینت سعی می کند با تکنیک Domain Fronting به آدرس سانسور شده Forbidden.example توسط یک DNS مجاز درخواستی ارسال کند)
سوالی که پیش می آید این است که چرا سایر شرکت هایی که سانسور شدن از Domain Fronting را پیاده سازی نکردند ؟ استفاده از سرویس های CDN با حجم کاربران زیاد، نیازمند پهنای باند قابل توجهی است که شامل هزینه خواهد بود و باید آن شرکت به سرویس دهنده CDN بابت مصرف پهنای، هزینه پرداخت کند، همچنین برای دور زدن سانسور باید از سرویس دهنده هایی که ترافیک زیادی از اینترنت را برای خود کرده اند استفاده کرد مثل گوگل، آمازون و ... که طبیعتا هزینه پهنای باند در این سرویس دهنده ها نسبت به سایرین گرانتر است.
تلگرام با تصمیم به دور زدن سانسور و پیاده سازی این تکنیک و با توجه به سیاست فعلی خود، در حال حاضر متحمل یک هزینه ی هنگفت و ضرر (مالی) است، به دلیل آنکه علاوه بر اینکه ترافیک کاربران بروی سرور های خود مشمول هزینه است همکنون باید تمام این ترافیک را از یک سرویس دهنده ی دیگر عبور دهد!
7 سرویس دهنده که می توان بروی آن ها DomainFronting پیاده سازی کرد :
Amazon CloudFront :هر گیگ در آمریکا و اروپا $0.085 / هر گیگ در آمریکا جنوبی : $0.25
- Microsoft Azure :هر گیگ $0.087
- Fastly :هر گیگ $0.19
- CloudFlare :مهم نبودن مصرف پهنای باند / فروش پلن ماهیانه
- Akamai :شارژ ماهیانه یک ترابایت $400 سپس هر گیگ $0.50
- Level 3 :هر گیگ 0.25$
- Google App Engine :هر گیگ $0.12
سرویس دهنده های نیازمند Reflector :
- Google App Engine
- Microsoft Azure
ساخت Reflector در Google App Engine با اسکریپت به زبان پایتون:
با یک اسکریپت ساده درخواست ورودی را به همان شکل به سرور مقصد بازتاب می کنیم و پاسخ آن را می توانید در Web View logs مشاهده کنید.
ابتدا یک پروژه جدید ساخته سپس یک فولدر برای ذخیره سازی پروژه درست کنید :
کد:
mkdir reflector cd reflector
در فولدر app engine فایلی با نام main.py وجود دارد که اسکریپت ما به زبان پایتون در این فایل قرار می گیرد :
کد:
import logging
import urllib
import webapp2
import urllib2
# change to your IP
redirector = "(insert you C2 domain here)"
class CommandControl(webapp2.RequestHandler):
def get(self, data):
url = https://+redirector+/+str(data)
try:
req = urllib2.Request(url)
req.add_header(User-Agent,"Mozilla/5.0 (Windows NT 10.0WOW64Trident/7.0rv:11.0) like Gecko")
for key, value in self.request.headers.iteritems():
req.add_header(str(key), str(value))
resp = urllib2.urlopen(req)
content = resp.read()
self.response.write(content)
except urllib2.URLError:
"Caught Exception, did nothing"
# handle a POST request
def post(self, data):
url = https://+redirector+/+str(data)
try:
req = urllib2.Request(url)
req.add_header(User-Agent,"Mozilla/5.0 (Windows NT 10.0WOW64Trident/7.0rv:11.0) like Gecko")
for key, value in self.request.headers.iteritems():
req.add_header(str(key), str(value))
# this passes on the data from CB
req.data = self.request.body
resp = urllib2.urlopen(req)
content = resp.read()
self.response.write(content)
except urllib2.URLError:
"Caught Exception, did nothing"
app = webapp2.WSGIApplication([
(r"/(.+)", CommandControl)
], debug=True)
به جای (insert you C2 domain here) آیپی یا دامین سرور اصلی ما قرار می گیرد که قرار است Request برای آن بازتاب شود :
کد:
redirector = "faranevis.com"
و در آخر کد ها را Deploy می کنیم :
کد:
gcloud app deploy
هیدر Host شما در درخواست به صورت زیر خواهد بود، در نتیجه در برنامه ی خود به جای استفاده از آدرس سرور از آدرس زیر استفاده می کنید ([appname] جایگزین نام اپ شما می شود)