كيفية اكتشاف مصافحة SSL (HTTPS) الواردة (تنسيق سلك SSL)؟

StackOverflow https://stackoverflow.com/questions/3897883

  •  29-09-2019
  •  | 
  •  

سؤال

أنا أكتب خادمًا يقبل اتصالات TCP الواردة. لنفترض أن الخادم قد قبل اتصال TCP ، وقد تلقى بالفعل 16 (أو نحو ذلك) بايت من العميل. معرفة تلك البايتات الـ 16 كيف يمكن أن يكتشف الخادم ما إذا كان العميل يريد بدء مصافحة SSL؟

لقد قمت بتجربة ، والتي أظهرت أنه في نظام Linux الخاص بي يتصل بـ LocalHost (إما 127.0.0.1 أو AF_UNIX) عبر SSL يجعل العميل يرسل المصافحة التالية (Hexdump) ، تليها 16 بايت عشوائي على ما يبدو:

8064010301004b0000001000003900003800003500001600001300000a07
00c000003300003200002f03008000000500000401008000001500001200
0009060040000014000011000008000006040080000003020080

كيف ينبغي أن يبحث الخادم عن هذه البايتات القليلة الأولى ، فقط لتكون قادرًا على تحديد ما إذا كان العميل يرسل مصافحة SSL؟ يجب أن يعود التحقيق بشكل صحيح لجميع مصافح SSL صالحة ، ويجب أن يعود خطأ مع احتمال كبير لرسالة أرسلها العميل والتي ليست مصافحة SSL. لا يُسمح باستخدام أي مكتبات (مثل OpenSSL) للتحقيق. يجب أن يكون المسبار رمزًا بسيطًا (مثل بضع عشرات الخطوط في C أو Python).

هل كانت مفيدة؟

المحلول 2

يمكنني معرفة ذلك بناءً على تنفيذ ClientHello.parse الطريقة فيhttp://tlslite.cvs.sourceforge.net/viewvc/tlslite/tlslite/tlslite/messages.py؟view=markup

أنا أعطي حلين هنا في بيثون. IsSSlClientHandshakeSimple هو regexp بسيطة ، والتي يمكن أن تسفر عن بعض الإيجابيات الخاطئة بسهولة تامة ؛ IsSslClientHandshake أكثر تعقيدًا: إنه يتحقق من اتساق الأطوال ، ونطاق بعض الأرقام الأخرى.

import re

def IsSslClientHandshakeSimple(buf):
  return bool(re.match(r'(?s)\A(?:\x80[\x0f-\xff]\x01[\x00-\x09][\x00-\x1f]'
                       r'[\x00-\x05].\x00.\x00.|'
                       r'\x16[\x2c-\xff]\x01\x00[\x00-\x05].'
                       r'[\x00-\x09][\x00-\x1f])', buf))

def IsSslClientHandshake(buf):
  if len(buf) < 2:  # Missing record header.
    return False
  if len(buf) < 2 + ord(buf[1]):  # Incomplete record body.
    return False
  # TODO(pts): Support two-byte lengths in buf[1].
  if ord(buf[0]) == 0x80:  # SSL v2.
    if ord(buf[1]) < 9:  # Message body too short.
      return False
    if ord(buf[2]) != 0x01:  # Not client_hello.
      return False
    if ord(buf[3]) > 9:  # Client major version too large. (Good: 0x03)
      return False
    if ord(buf[4]) > 31:  # Client minor version too large. (Good: 0x01)
      return False
    cipher_specs_size = ord(buf[5]) << 8 | ord(buf[6])
    session_id_size = ord(buf[7]) << 8 | ord(buf[8])
    random_size = ord(buf[9]) << 8 | ord(buf[10])
    if ord(buf[1]) < 9 + cipher_specs_size + session_id_size + random_size:
      return False
    if cipher_specs_size % 3 != 0:  # Cipher specs not a multiple of 3 bytes.
      return False
  elif ord(buf[0]) == 0x16:  # SSL v1.
    # TODO(pts): Test this.
    if ord(buf[1]) < 39:  # Message body too short.
      return False
    if ord(buf[2]) != 0x01:  # Not client_hello.
      return False
    head_size = ord(buf[3]) << 16 | ord(buf[4]) << 8 | ord(buf[5])
    if ord(buf[1]) < head_size + 4:  # Head doesn't fit in message body.
      return False
    if ord(buf[6]) > 9:  # Client major version too large. (Good: 0x03)
      return False
    if ord(buf[7]) > 31:  # Client minor version too large. (Good: 0x01)
      return False
    # random is at buf[8 : 40]
    session_id_size = ord(buf[40])
    i = 41 + session_id_size
    if ord(buf[1]) < i + 2:  # session_id + cipher_suites_size doesn't fit.
      return False
    cipher_specs_size = ord(buf[i]) << 8 | ord(buf[i + 1])
    if cipher_specs_size % 2 != 0:
      return False
    i += 2 + cipher_specs_size
    if ord(buf[1]) < i + 1: # cipher_specs + c..._methods_size doesn't fit.
      return False
    if ord(buf[1]) < i + 1 + ord(buf[i]): # compression_methods doesn't fit.
      return False
  else:  # Not SSL v1 or SSL v2.
    return False
return True

نصائح أخرى

يرسل العميل دائمًا ما يسمى رسالة Helloclient أولاً. يمكن أن يكون بتنسيق SSL 2 أو تنسيق SSL 3.0 (نفس التنسيق كما في TLS 1.0 و 1.1 و 1.2).

وهناك أيضًا احتمال أن يقوم العملاء SSL 3.0/TLS 1.0/1.1/1.2 بإرسال Helloclient بالتنسيق الأقدم (SSL 2) ، فقط مع رقم الإصدار الأعلى في البيانات. لذلك ، يعد اكتشاف SSL 2 Helloclient ضروريًا للعملاء الجدد أيضًا. (على سبيل المثال ، يقوم تطبيق Java SSL بذلك)

دعنا نقول "ب" هو المخزن المؤقت الخاص بك. حاولت تخطيط تنسيق الرسالة.

SSL 2

+-----------------+------+-------
| 2 byte header   | 0x01 | etc.
+-----------------|------+-------
  • B [0] & 0x80 == 0x80 (وهذا يعني أن البت الأكثر أهمية من B [0] هو '1')

  • ((B [0] & 0x7f) << 8 | B [1])> 9 (إنه menas البتات المنخفضة 7 من B [0] مع B [1] طول البيانات. يمكنك الحصول على أقل في المخزن المؤقت الخاص بك ، لذلك لا يمكنك التحقق منها. ولكن من تنسيق الرسالة ، نعلم أن هناك 3 حقلًا من 2 بايت (حقول الطول) ، وعنصر واحد على الأقل في حقل قائمة التشفير (من الحجم 3). لذلك يجب أن يكون هناك 9 بايت على الأقل ( طول البيانات> = 9).

  • B [2] يجب أن يكون 0x01 (نوع الرسالة "ClientHello")

SSL 3.0 أو TLS 1.0 و 1.1 و 1.2

+-------+------------------+------------------+--------+------
| 0x16  | 2 bytes version  |  2 bytes length  |  0x01  |  etc.
+-------+------------------+------------------+--------+------
  • B [0] == 0x16 (نوع الرسالة "مصافحة SSL")

  • B [1] يجب أن يكون 0x03 (أحدث إصدار رئيسي ، ولكن من يدري في المستقبل؟)

  • B [5] يجب أن يكون 0x01 (رسالة بروتوكول المصافحة "Helloclient")

كمرجع ، يمكنك أن ترى http://www.mozilla.org/projects/security/pki/nss/ssl/draft02.html و http://tools.ietf.org/html/rfc4346

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top