1 पॉइंट द्वारा GN⁺ 2024-05-22 | 2 टिप्पणियां | WhatsApp पर शेयर करें
  • दस्तावेज़ टेम्पलेट से email, text message और PDF बनाने वाले सिस्टम में, एक खास ग्राहक को भेजे गए email body में ही पूर्ण विराम गायब होने की समस्या हुई
  • टेम्पलेट के मूल स्रोत, preview और PDF में पूर्ण विराम मौजूद था, लेकिन ग्राहक-विशेष placeholder values को वास्तविक डेटा से बदलने के बाद केवल कुछ खास line length पर ही यह दोबारा दिखाई देता था
  • custom SMTP client ने line length सीमित करते हुए पूर्ण विराम को अगली पंक्ति के पहले अक्षर पर धकेल दिया, और SMTP के dot transparency नियम के कारण server ने उस पूर्ण विराम को हटा दिया
  • सुधार इस तरह किया गया कि जिन पंक्तियों की शुरुआत पूर्ण विराम से होती है और उसके बाद अन्य अक्षर आते हैं, उनके आगे client एक और पूर्ण विराम जोड़ दे
  • वही SMTP client code साझा करने वाली दूसरी टीम ने patch लागू नहीं किया, इसलिए कुछ ग्राहकों को ऐसा email भेजा गया जिसमें मासिक insurance premium $27.00 की जगह $2700 दिखाई दे रहा था, और bug को तुरंत ठीक किया गया

केंद्रीय टेम्पलेट सिस्टम से शुरू हुई समस्या

  • लगभग 7 साल पहले, एक client कई Microsoft Word templates में बिखरे दस्तावेज़ों को एक ही सिस्टम में समेकित करना चाहता था
  • पुरानी प्रक्रिया में कर्मचारी दस्तावेज़ के placeholder को हाथ से नाम, surname आदि से बदलते थे, और पुराने terms, पुराना company logo, तथा गलत font वाले templates भी साथ-साथ चलते रहते थे, जिससे प्रबंधन कठिन हो गया था
  • नया सिस्टम दस्तावेज़ templates को केंद्रीय रूप से प्रबंधित करता था, और उनके आधार पर PDF documents, text messages और email body बनाता था
  • नए ग्राहक के welcome message के लिए delivery method के अनुसार अलग-अलग templates हो सकते थे
    • email version में HTML tables और basic styling का उपयोग किया जा सकता था
    • डाक से भेजे जाने वाले version में infographic शामिल हो सकता था
    • text message version में केवल छोटा welcome message रखा जा सकता था

सिर्फ कुछ ग्राहकों के लिए गायब हुआ पूर्ण विराम

  • सिस्टम चालू हुए कुछ महीने, या एक साल से अधिक समय बीतने के बाद, एक manager ने बताया कि एक खास ग्राहक को भेजे गए email body में एक पूर्ण विराम गायब था
  • वही email किसी दूसरे ग्राहक को भेजने पर पूर्ण विराम गायब नहीं हो रहा था, इसलिए इसे साधारण template error मानना कठिन था
  • template source code में वह पूर्ण विराम वास्तव में मौजूद था
  • production template की copy लेकर local environment में email body का preview बनाने पर भी पूर्ण विराम दिखाई दे रहा था, और उसी template से बने print version में भी वह सही दिख रहा था
  • local environment में email को localhost के एक खास port पर भेजा जाता था, और SMTP4dev जैसे fake SMTP server तथा Outlook से email की जाँच की जाती थी
  • local environment से पहली बार भेजे गए email को Outlook में देखने पर भी पूर्ण विराम सही दिखाई दे रहा था

ग्राहक-विशेष डेटा से बनी पुनरुत्पादन की शर्तें

  • template email, PDF और text message बनाते समय ग्राहक के नाम, surname जैसे placeholder values को वास्तविक डेटा से बदलता था
  • एक ही template होने पर भी हर ग्राहक को भेजे जाने वाले email body की content length अलग हो सकती थी
  • जिस ग्राहक के साथ समस्या हुई थी, उसके लिए इस्तेमाल हुए वास्तविक placeholder values को ढूँढ़कर local environment में उसी डेटा के साथ email फिर से भेजा गया, तो Outlook में पूर्ण विराम गायब होने की घटना दिखी
  • समस्या उस ग्राहक के email की विशिष्ट body length और content पर निर्भर थी
  • शुरुआत में यह जाँचा गया कि template का पूर्ण विराम character encoded है या वह वास्तव में कोई दूसरा character तो नहीं, लेकिन कारण यह नहीं था
  • template के भीतर पूर्ण विराम की स्थिति एक अक्षर आगे-पीछे करने पर Outlook में वह फिर दिखाई देने लगा, और line position एक महत्वपूर्ण सुराग बन गई

SMTP line length और dot transparency

  • debugging से पता चला कि email को database में सहेजने वाला code, placeholder को ग्राहक जानकारी से बदलने के अलावा, template में कोई बदलाव नहीं कर रहा था
  • इसके बाद जाँच का दायरा उस cron job तक सिमट गया जो नियमित रूप से recipients लाकर email भेजती थी
  • cron job जिस code को call करती थी, उसका कुछ हिस्सा पुराने project से लाया गया था, और उसी में custom SMTP client implementation शामिल थी
  • उस code में एक function था जो email body की हर line को एक निश्चित character count से लंबा न होने देने के लिए उसे तोड़ देता था
  • यह व्यवहार SMTP specification की line length limit से जुड़ा था
    • text line की अधिकतम कुल लंबाई <CRLF> सहित 1000 octets है
    • transparency के लिए duplicate किए गए leading periods इस गणना में शामिल नहीं होते
    • SMTP Service Extensions के जरिए यह संख्या बढ़ सकती है
  • समस्या वाले email body में line length limit के कारण पूर्ण विराम अगली line के पहले character पर चला गया
  • SMTP specification में mail data समाप्ति संकेत एक ऐसे line के रूप में माना जाता है जिसमें केवल एक पूर्ण विराम हो
  • SMTP का dot transparency नियम, पूर्ण विराम से शुरू होने वाली body lines को अलग तरीके से संभालता है
    • SMTP client को mail text line भेजने से पहले देखना चाहिए कि पहला character पूर्ण विराम है या नहीं, और यदि है तो line की शुरुआत में एक और पूर्ण विराम जोड़ना चाहिए
    • SMTP server किसी ऐसी line को, जिसमें केवल एक पूर्ण विराम हो, mail data का अंत मानता है
    • यदि पहला character पूर्ण विराम हो और उसी line में अन्य character भी हों, तो server पहले character को हटा देता है
  • custom SMTP client में उन lines के लिए एक अतिरिक्त पूर्ण विराम जोड़ने की प्रक्रिया नहीं थी जो पूर्ण विराम से शुरू होती थीं, इसलिए receiving SMTP server ने पहला पूर्ण विराम हटा दिया और body का वास्तविक पूर्ण विराम गायब हो गया

सुधार और देर से सामने आया प्रभाव

  • सुधार यह था कि जब कोई line पूर्ण विराम से शुरू हो और उसी line में अन्य character भी हों, तब client एक और पूर्ण विराम जोड़ दे
  • ऐसा भेजने पर receiving SMTP server पहला पूर्ण विराम हटा देता है, लेकिन body में मूल पूर्ण विराम बना रहता है
  • समस्या वाले ग्राहक की वही recipient जानकारी लेकर local environment में मूल email फिर भेजा गया, तो पूर्ण विराम अब गायब नहीं हुआ
  • सुधार deploy होने के बाद, क्योंकि वही SMTP client code पुराने project से लेकर दूसरी टीमों ने भी इस्तेमाल किया था, उन्हें भी इस bug के बारे में बताया गया
  • कुछ महीनों बाद दूसरी टीम का सिस्टम अभी तक patch नहीं हुआ था, और उसने ग्राहकों को नए monthly insurance premium की जानकारी देने वाले कई महत्वपूर्ण emails भेज दिए
  • कुछ emails में monthly premium का decimal separator period ठीक line के पहले character की स्थिति में आ गया और गायब हो गया
  • नतीजतन, कुछ ग्राहकों को ऐसा email मिला जिसमें नया premium $27.00 नहीं बल्कि $2700 दिखाई दे रहा था
  • यह bug email body की हर line की length पर निर्भर था, और केवल उन्हीं कुछ ग्राहकों के साथ हुआ जिनके नाम और surname की लंबाई ठीक उसी तरह मेल खाती थी
  • कारण पहले से पता होने के कारण, उस टीम के code को तुरंत patch कर दिया गया

2 टिप्पणियां

 
surfindia 2024-05-22

लगता है कि शीर्षक में period को full stop की बजाय अवधि के रूप में लिया गया है, हाहा।

 
GN⁺ 2024-05-22
Hacker News की राय
  • इस code के कुछ हिस्से SMTP client को सीधे implement कर रहे थे, और मूल वजह वहीं लगती है
    protocol को सही-सही implement करना कठिन है, और लेख में बताए bug जैसी चीजें आम हैं
    अगर ठीक से implement की गई SMTP client library होती, तो input text में full stop कहाँ है इससे फर्क पड़े बिना वह SMTP rules के मुताबिक encode करती, और template layer को SMTP की चिंता करने की जरूरत नहीं होती

    • असली समस्या protocol से ज्यादा, उस protocol को संभालने के cowboy-style approach में है
      SMTP rules के मुताबिक text लेकर encode करना कठिन नहीं है, लेकिन पहले यह पता होना चाहिए कि ऐसी processing जरूरी है
      SQL injection, XSS जैसी असंख्य errors और security vulnerabilities भी उसी गलती, यानी string concatenation, से पैदा होती हैं
      SQL queries में values को query template से bind करने का काम untyped string space में नहीं, “SQL space” में होना चाहिए, और SELECT * FROM foo WHERE foo.bar = + $userData जैसी serialized SQL string सीधे बनाना गलत तरीका है
      HTML templates भी इसी तरह string representation के बजाय document tree level पर handle किए जाएँ, तो बेवकूफाना vulnerabilities से बचा जा सकता है
      email में full stop गायब होने से बचना है तो SMTP pipeline के बीच में structure-less text inject न करें, और जिस abstraction level पर काम कर रहे हैं उसका सम्मान करें
      इस संदर्भ में langsec भी देखने लायक है
    • असली समस्या यह है कि SMTP एक “plain text” protocol है जिसमें in-band signaling शामिल है
      “सिर्फ एक full stop वाली line” को literal line नहीं, बल्कि control sequence के रूप में define किया गया है, इसलिए ऐसा होता है
      SMTP अनावश्यक रूप से complex design का उदाहरण है, और implementation bugs भी उसी complexity को दिखाते हैं
      मैं इसे खुद implement करने की सलाह नहीं दे रहा, लेकिन SMTP इतना कठिन भी नहीं होना चाहिए कि अकेले सही तरीके से implement करना मुश्किल हो जाए
    • सुनने में अच्छा idea लगता है, लेकिन मान लीजिए आपने एक SMTP library ले ली और वह library 5 dependencies खींच लाती है, फिर हर dependency अपनी 3 transitive dependencies लाती है, और उनमें से एक असल में सब-कुछ करने वाला toolbox project हो सकता है जिसका केवल 1% इस्तेमाल होता है
      बाकी सब dead weight है, फिर भी कभी call न होने वाले functions की वजह से 20 और dependencies आ जाती हैं, और देखते-देखते codebase कई MB फूल जाता है, और किसी ऐसी library के CVE alerts मिलने लगते हैं जिसके इस्तेमाल का आपको पता भी नहीं था
    • https://en.wikipedia.org/wiki/Jamie_Zawinski#Zawinski's_Law
  • तकनीकी हिस्से को दूसरे लोग पहले ही बेहतर तरीके से cover कर चुके हैं, लेकिन एक किस्सा याद आता है कि sentence के अंत में एक full stop जैसी छोटी चीज कितनी महत्वपूर्ण हो सकती है
    जर्मनी में, जहाँ मैं काम करता हूँ, नौकरी छोड़ते समय “Zeugnis” मांगना आम है—यह एक recommendation letter होता है जिसमें किए गए काम और employee evaluation लिखे होते हैं, और job search में आम तौर पर मांगा जाने वाला महत्वपूर्ण document है
    जाहिर है, कोई employee “यह व्यक्ति आलसी है, इसे hire न करें” जैसी line स्वीकार नहीं करेगा, इसलिए तारीफ जैसा दिखने वाला एक तरह का code “Zeugnissprache” बन गया
    उस code में से एक यह है कि अगर आखिरी sentence में full stop नहीं है, तो मतलब होता है “यहाँ लिखा सब ignore करें, यह व्यक्ति बहुत खराब है”
    पिछली नौकरी के बाद मैंने अपना Zeugnis lawyer से review करवाया, और सभी evaluations positive थीं, फिर भी शायद लापरवाही से आखिरी sentence में full stop छूट गया था

    • recommendation letters में secret code इस्तेमाल होता है, यह urban legend है
      HR लोगों के पास संभावित competitors के साथ इस्तेमाल करने के लिए secret codes बनाने का कोई incentive नहीं होता, और नए HR staff को सिखाते हुए भी उसे secret बनाए रखना भी तर्कसंगत नहीं है
      ऐसी legends इसलिए बनती हैं क्योंकि HR किसी व्यक्ति के problematic होने की बात बहुत खुलकर नहीं लिख सकता
      अगर positive लिखने को कुछ नहीं है, तो punctuality जैसी साधारण खूबियों की तारीफ कर दी जाती है; यह secret code कम और HR-style “bless their heart” ज्यादा है
      अगर lawsuit हो जाए, तो निकलने की गुंजाइश रहती है: “जज साहब, यह तो अच्छी बात थी! वे हमेशा समय पर आते थे!”
    • “अगर आखिरी sentence में full stop नहीं है, तो यहाँ लिखा सब ignore करें, यह व्यक्ति बहुत खराब है”—सोचता हूँ, आखिर इसमें गलत क्या हो सकता है
    • उत्सुकता है कि क्या आपने performance review documents में भी check किया कि full stop गायब था या नहीं
  • समझ नहीं आता कि email भेजने वाली cron job को अपना खुद का SMTP client क्यों implement करना चाहिए
    बस mailutils का mail जैसा program इस्तेमाल कर लें
    deliverability के नजरिए से भी socket के ऊपर skeleton-level SMTP interaction खुद बनाना शुरुआत से ही अव्यावहारिक है
    आजकल आप किसी भी mail exchange host से सीधे connect करके mail नहीं भेज सकते; आम तौर पर ISP द्वारा दिए गए किसी खास SMTP relay host से connect करना पड़ता है
    इसके लिए TLS connection, authentication वगैरह सब implement करना होगा
    थोड़ी irony यह है कि cron खुद भी पहले से mail भेजना जानता है
    cron job का output owner को mail से भेजा जाता है, और कुछ cron implementations crontab के MAILTO variable जैसी चीज से recipient address बदलने देती हैं

    • mail भेजते समय host के MTA का इस्तेमाल करना चाहिए, फिर भी असल में बहुत-सी चीजें अपना built-in SMTP client रखती हैं
      वजह यह है कि “उस चीज” को इस्तेमाल करना चाहने वाला user शायद SMTP server address डाल सकता है, लेकिन program के पास यह भरोसा करने का कोई तरीका नहीं कि sendmail जैसा sending MTA ठीक से configured है
      कंपनियों में ऐसे servers बड़ी संख्या में होते हैं जो system mail नहीं भेज सकते, और कई बार वह स्थिति program author या user के control से बाहर होती है
      mail configuration DNS, encryption, policy जैसी prerequisites वाला specialized area है, इसलिए wallet app जैसी किसी चीज से mail भेजवाने के मकसद भर के लिए यह बहुत ज्यादा है
      “system administrator से संपर्क करें” बड़े या छोटे पैमाने पर अक्सर practical विकल्प नहीं होता
      यह अच्छा कारण नहीं है, लेकिन वास्तविक कारण जरूर है
    • ऐसी दुनिया नहीं है जहाँ भरोसा किया जा सके कि system में पहले से mail भेजने वाला binary मौजूद होगा, लेकिन फिर भी मैं इसे खुद नहीं बनाऊँगा
      ज्यादातर languages में standard library में न भी हो, तो भी इस्तेमाल लायक SMTP client libraries काफी मिल जाती हैं
    • लगता है यह भी Zawinski's Law का case है
  • यहाँ दो बड़ी बुरी आदतें दिखती हैं
    पहली, जैसा कई लोगों ने बताया, standards को आधे-अधूरे ढंग से implement न करें
    अगर खुद implement करना ही है, तो जरूरी सावधानी और मेहनत लगाएँ, या पहले से बनी library इस्तेमाल करें
    दूसरी, dependencies को vendor न करें
    जो libraries आप इस्तेमाल करते हैं, उन्हें नियमित रूप से और समय पर update करना चाहिए, “जब जरूरत पड़े तभी” नहीं
    updates में देरी करने या उनसे पूरी तरह बचने पर, upstream में पहले से fix हो चुके bugs भी उन लोगों के लिए बड़ी समस्या बन सकते हैं जो सोचते हैं कि update सिर्फ तब करना चाहिए जब उन्हें खुद समस्या दिखे

    • dependencies को vendor न करने का विकल्प और भी खराब लगता है
      तब application की stability upstream changes के सामने खुली रहती है, और वे changes code तोड़ सकते हैं
      हो सकता है fixes तुरंत न मिलें, लेकिन मेरी नजर में अनचाही instability और अतिरिक्त risk लाने के बजाय यह जानना बेहतर है कि मैं किसी fix की जरूरत की वजह से change कर रहा हूँ
      मैं “अगर टूटा नहीं है तो ठीक मत करो” वाली तरफ हूँ
  • आजकल लगता है कि बहुत से लोग terminal से सीधे interact करके basic protocols नहीं सीखते
    SMTP मूल रूप से शायद ऐसे ही manual interaction को ध्यान में रखकर बनाया गया था, और जिसने इसे कुछ समय तक सच में ऐसे इस्तेमाल किया हो, उसके लिए message खत्म करने वाली “एक लाइन में सिर्फ एक dot” वाली बात हमेशा के लिए याद में बैठ जाती है
    इससे जुड़ी escaping भी कई programmers के लिए अनजाना concept लगती है
    ऊपर की स्थिति देखकर “अगर मैं ऐसी email भेजना चाहूँ जिसमें सिर्फ एक dot वाली line हो तो क्या?” यह सवाल न पूछने वाले भी बहुत लोग हैं, लेकिन एक और बड़ा समूह है जिसे यह सवाल बहुत logical और समझने में आसान लगेगा

    • पिछले 30 साल में software developers का कोई meaningful प्रतिशत अगर इस तरह सीखा हो, तो मुझे उल्टा आश्चर्य होगा
  • dot stuffing जरूरी है
    SMTP https://www.rfc-editor.org/rfc/rfc5321#section-4.5.2
    POP3 में भी है https://www.rfc-editor.org/rfc/rfc1939#page-8

  • network protocol implementation debug करने का अपना अनुभव याद आया। खास तौर पर पुराने लोगों के लिए AppleTalk NBP था
    मैंने सब code कर दिया था, लेकिन मेरे packets reject हो रहे थे, यानी चुपचाप drop हो जाते थे, और असली Apple implementation के packets pass हो रहे थे
    अच्छे packet और बुरे packet को computer screen पर रखकर byte by byte compare किया, लेकिन problem नहीं मिली; checksum सहित शुरू से अंत तक वे बिल्कुल एक जैसे थे
    ऑफिस से निकलने का समय हो गया, तो बाद में देखने के लिए उन बेवकूफ चीजों को print करने का फैसला किया, और print करते ही error दिख गया
    मेरा version दो pages का था, और सही implementation एक page की थी
    data भेजने से पहले buffer को ठीक से खाली नहीं किया था। mbuf ऐसी ही चीज है
    आज भी सोचकर हँसी आती है

  • “We are happy to welcome you to our family.” वाली line line length limit के पास भी नहीं जाती
    लगता है कुछ और हो रहा था, जैसे शायद पूरा content वास्तव में HTML MIME attachment रहा हो
    इस तरह ... lots of text ... के बाद We are happy to welcome you to our family. रहा हो सकता है
    लेकिन HTML को मनमाने ढंग से lines में काटने पर tags टूट जाते हैं

    • यह सिर्फ example था, और सही character count वाला असली example न दे पाने के लिए माफ़ी
    • टूटे हुए HTML email पाने वाले ज्यादातर लोग बस यह नोटिस करेंगे कि email format अजीब है, कंपनी को ऐसी कंपनी मानेंगे जो पढ़ने लायक email भी ठीक से नहीं लिख सकती, company capability assessment घटाएँगे और अगली email पर चले जाएँगे
      कंपनी शायद उस छोटी-सी समस्या से पूरी तरह अनजान ही रहेगी
    • quoted-printable encoding के soft line breaks इस्तेमाल करने पर HTML tags तोड़े बिना भी lines को मनमाने ढंग से बाँटा जा सकता है
      quoted-printable में CRLF सहित अधिकतम 78 characters की limit होनी चाहिए, लेकिन email clients आम तौर पर उदार होते हैं
  • अगर किसी ने dot stuffing पहली बार सुना है, तो email की दुनिया में और कौन-कौन सी डरावनी चीजें हैं, इस पर यकीन करना मुश्किल होगा
    header folding, local part में quotes handling, IPv6 literals जैसी चीजें हैं

    • IPv6 literals में क्या समस्या है, यह जानने की उत्सुकता है
  • जैसे ही पढ़ा कि यह पिछले project से उधार लिया गया SMTP client code था, मुझे लगा अंत में यह निकलेगा कि दूसरी team ने अभी तक यह bug patch नहीं किया है