متصل کردن گواهی (Certificate Pinning) به برنامه اندروید یا ios خود

ترجمه و تالیف : پوریا شریفی
تاریخ انتشار : 19 مرداد 99
خواندن در 1 دقیقه
دسته بندی ها : اندروید

وقتی ما توسعه دهندگان در حال توسعه هر نوع نرم‌افزاری هستیم، نمی‌توان امنیت را فراموش کرد. حداقل معیار امنیتی که باید از آن استفاده کنیم HTTPS به عنوان پروتکل برای به اشتراک گذاری اطلاعات بین مشتری (در این حالت یک برنامه اندروید/ios) و یک سرور است؛ به‌دنبال آن یک پروتکل رمزنگاری بروز شده مانند (TLS 1.2(SSL 3.0 آسیب پذیر است!

ممکن است فکر کنید که استفاده از HTTPS کافی است اما در بعضی موارد مانند برنامه‌های بانکی، که ممکن است داده‌های حساس بین مشتری و سرور ارسال شود، می‌تواند خطرناک باشد.

به طور پیش‌فرض هنگام برقراری اتصال TLS، کلاینت دو مورد را بررسی می‌کند:

  • گواهی سرور با نام میزبان درخواستی مطابقت دارد
  • گواهی سرور دارای زنجیره‌ای از حقایق براساس گواهی ریشه است

آنچه انجام نمی‌دهد بررسی این است که آیا این گواهی، گواهی خاصی است که می‌دانید سرور از آن استفاده می‌کند، و این یک آسیب‌پذیری امنیتی احتمالی  است: اگر کلاینت به خطر بی‌افتد و یک گواهی ناامن نصب شود، کسی می‌تواند یک حمله بین آن انجام دهد.

متصل کردن گواهی (Certificate Pinning) به برنامه اندروید یا ios خود

راه‌حل این مشکل، متصل کردن گواهی است: ذخیره گواهی در کلاینت برای اطمینان از اینکه هر درخواست SSl ساخته شده مطابق با سرور ما است. بگذارید چگونگی این کار را در هر دو برنامه اندروید و ios برای شما توضیح دهم.

اندروید

کتابخانه Okhttp یک کلاس CertificatePinner ارائه می‌دهد تا به نمونه OkHttpClient اضافه شود. آسان‌ترین راه برای متصل کردن به میزبان این است که pinning را بر روی پیکربندی نقض شده فعال کنیم و در صورت عدم موفقیت اتصال پیکربندی مورد انتظار خوانده شود.

CertificatePinner certificatePinner = new CertificatePinner.Builder()
         .add("mydomain.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
         .build();
     OkHttpClient client = OkHttpClient.Builder()
         .certificatePinner(certificatePinner)
         .build();

پس از اجرای یک درخواست، این پیام را روی کنسول مشاهده خواهید کرد:

javax.net.ssl.SSLPeerUnverifiedException: Certificate pinning failure!
   Peer certificate chain:
     sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=: CN=mydomain.com, OU=PositiveSSL
     sha256/klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY=: CN=COMODO RSA Secure Server CA
     sha256/grX4Ta9HpZx6tSHkmCrvpApTQGo67CYDnvprLg5yRME=: CN=COMODO RSA Certification Authority
     sha256/lCppFqbkrlJ3EcVFAkeip0+44VaoJUymbnOaEUk7tEU=: CN=AddTrust External CA Root
   Pinned certificates for mydomain.com:
     sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
   at okhttp3.CertificatePinner.check(CertificatePinner.java)
   at okhttp3.Connection.upgradeToTls(Connection.java)
   at okhttp3.Connection.connect(Connection.java)
   at okhttp3.Connection.connectAndSetOwner(Connection.java)

این exception باعث می‌شود شناسه کلید عمومی گواهی سرور برای شما فراهم شود. آن‌ها را روی CertificatePinner بچسبانید و تمام!

CertificatePinner certificatePinner = new CertificatePinner.Builder()
       .add("mydomain.com", "sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=")
       .add("mydomain.com", "sha256/klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY=")
       .add("mydomain.com", "sha256/grX4Ta9HpZx6tSHkmCrvpApTQGo67CYDnvprLg5yRME=")
       .add("mydomain.com", "sha256/lCppFqbkrlJ3EcVFAkeip0+44VaoJUymbnOaEUk7tEU=")
       .build();

ios

راه‌حل ios چندان ساده نیست، زیرا باید خود گواهی را درون برنامه خود ذخیره کنید. من از Alamofire به عنوان کتابخانه HTTP در سوئیفت استفاده می‌کنم.

ابتدا باید گواهی سرور را با فرمت .der دریافت کنید و آن‌را به پروژه ios خود اضافه کنید.

openssl s_client -showcerts -servername mydomain.com -connect mydomain.com:
443 </dev/null | openssl x509 -outform DER > mydomainCert.der

و اکنون بیایید اتصال گواهی را فعال کنیم: برای انجام این کار به هر دو شیء ServerTrustPolicy و SessionManager نیاز داریم. مورد اول نام میزبان و گواهی‌هایی که در این فرایند استفاده می‌شوند را تعریف می‌کند.

var serverTrustPolicies = [
    "mydomain.com": .pinCertificates(
    certificates: ServerTrustPolicy.certificates(),
    validateCertificateChain: true,
    validateHost: true
  ),
]

ServerTrustPolicy.certificates() کلیه گواهی‌های ذخیره شده را برمی‌گرداند و booleanها زنجیره گواهی و نام میزبان را تایید می‌کنند.

در آخر با استفاده trust policy یک شیء SessionManger ایجاد کنید:

var sessionManager = SessionManager(serverTrustPolicyManager:
 ServerTrustPolicyManager(policies: serverTrustPolicies!))

تمام شد! برای اجرای درخواست فقط از این شیء sessionManger استفاده کنید.

sessionManager.request("https://mydomain.com/api", method: .get, headers: headers)...

روش جدید برای پیاده‌سازی آن در ios

TrustKit یک کتابخانه منبع‌باز برای پیاده‌سازی اتصال SSL است. این یک راه‌حل آسان‌تر و انعطاف‌پذیرتر نسبت به استفاده از ServerTrustPolicy است.

هنگامی که یکبار TrustKit در برنامه ادغام شد، ما فقط باید آن‌را فعال کنیم، به عنوان مثال در فایل AppDelegate.

let trustKitConfig = [
    kTSKEnforcePinning: true,
    kTSKIncludeSubdomains: true,
    kTSKSwizzleNetworkDelegates: false,
    kTSKPinnedDomains: [
        "mydomain.com": [
            kTSKPublicKeyAlgorithms: [kTSKAlgorithmRsa2048,     kTSKAlgorithmRsa4096],
            kTSKPublicKeyHashes: [
                "afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=",
                "klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY=",
                "grX4Ta9HpZx6tSHkmCrvpApTQGo67CYDnvprLg5yRME="
            ],
          ]
        ]
    ] as [String : Any]
        TrustKit.initSharedInstance(withConfiguration:trustKitConfig)

بدین ترتیب، اجرای آن مانند اندروید است: ما گواهی .der و ServerTrustPolicy را فراموش می‌کنیم و اکنون از کلیدهای عمومی استفاده می‌کنیم، که راهی انعطاف‌‌پذیرتر برای پیاده‌سازی اتصال گواهی است زیرا نیازی به فایل به روز شده گواهی نداریم.

منبع

گردآوری و تالیف پوریا شریفی
آفلاین
user-avatar

ابتدا که با برنامه‌نویسی آشنا شدم به سمت php و طراحی وب رفتم، بعد از اون به توسعه‌ی اندروید علاقه‌مند شدم و تقریبا ۲ سال است که مشغول به برنامه‌نویسی اندروید هستم، همچنین عاشق یادگیری چیزهای جدید هستم.

دیدگاه‌ها و پرسش‌ها

برای ارسال نظر لازم است ابتدا وارد سایت شوید
در حال دریافت نظرات از سرور، لطفا منتظر بمانید