2011-09-06 13 views
27

मैं जानना चाहता हूं कि इनमें से कौन सा विकल्प उपयोग करने के लिए अधिक सुरक्षित है:Sprintf/snprintf का कौन सा अधिक सुरक्षित है?

#define MAXLEN 255 
char buff[MAXLEN + 1] 
  1. sprintf(buff, "%.*s", MAXLEN, name)

  2. snprintf(buff, MAXLEN, "%s", name)

मेरी समझ यह है कि दोनों समान हैं। कृपया सुझाव दे।

+0

# 2 से 'MAXLEN + 1' बदलें और वे सभी मामलों में 'buff' में लिखने में समान होंगे) (स्ट्रेल मान' स्ट्रेल (नाम)> 255') अलग होगा। –

उत्तर

0

दोनों आप जो परिणाम चाहते हैं उसे देंगे, लेकिन snprintf अधिक सामान्य है, और आपकी स्ट्रिंग को ओवररन्स से सुरक्षित रखेगा चाहे प्रारूप स्ट्रिंग दी गई हो।

इसके अलावा, क्योंकि snprintf (या उस बात के लिए sprintf) एक अंतिम \0 कहते हैं, आप स्ट्रिंग बफर एक बाइट बड़ा char buff[MAXLEN + 1] बनाना चाहिए,।

+1

यह मामला नहीं है। स्नप्रिंटफ़ डॉक से: "फ़ंक्शंस snprintf() और vsnprintf() अधिकांश आकार बाइट्स पर लिखते हैं (जिसमें शून्य बाइट ('\ 0') को समाप्त करना शामिल है)।" – Chriszuma

25

आपके द्वारा दिए गए दो भाव समकक्ष: sprintf लिखने के लिए अधिकतम बाइट निर्दिष्ट करने का कोई तर्क नहीं लेता है; यह बस एक गंतव्य बफर, एक प्रारूप स्ट्रिंग, और तर्क का एक गुच्छा लेता है। इसलिए, यह आपके बफर की जगह के मुकाबले अधिक बाइट्स लिख सकता है, और ऐसा करने में मनमाने ढंग से कोड लिखना।

  1. फॉर्मेट स्पेसिफायर लंबाई को दर्शाता है, यह strlen के बराबर की चर्चा करते हुए है;: %.*s एक संतोषजनक समाधान वजह से नहीं है यह स्ट्रिंग में वर्णों की संख्या का एक उपाय है, इसकी स्मृति में इसकी लंबाई नहीं है (यानी यह शून्य टर्मिनेटर की गणना नहीं करता है)।
  2. प्रारूप स्ट्रिंग में कोई भी परिवर्तन (उदाहरण के लिए, एक नई लाइन जोड़ना) बफर ओवरफ्लो के संबंध में sprintf संस्करण के व्यवहार को बदल देगा। snprintf के साथ, एक निश्चित, स्पष्ट अधिकतम प्रारूप स्ट्रिंग या इनपुट प्रकारों में परिवर्तनों के बावजूद सेट किया गया है।
+0

दरअसल, लगभग 1, मुझे गलत था - यह अधिकतम वर्णों को निर्दिष्ट करता है (लेकिन '\ 0' की गणना किए बिना)। मैंने तदनुसार अपना जवाब संपादित कर लिया है। –

+0

धन्यवाद - मुझे याद आया कि उस प्रारूप विनिर्देशक के साथ कुछ समस्या है, और माना जाता है कि आप सही थे :-P – azernik

+1

ठीक है, यह सब इस बात पर निर्भर करता है कि ओपी का सवाल किस तरह की सुरक्षा के बारे में है। औपचारिक रूप से एक उचित रूप से इस्तेमाल किया जाने वाला 'स्प्रिंटफ़' इस विशिष्ट मामले में' snprintf' के रूप में सुरक्षित है। इस जवाब में आप किस बारे में बात कर रहे हैं आलसी/अक्षम प्रोग्रामर से सुरक्षा की कमी है। क्या ओपी सुरक्षा के इस पक्ष के बारे में पूछ रहा था, मुझे नहीं पता। – AnT

2

आपका स्पिंटफ स्टेटमेंट सही है, लेकिन मैं सुरक्षा उद्देश्य के लिए इसका उपयोग करने के लिए पर्याप्त आत्मविश्वास नहीं रखूंगा (उदाहरण के लिए एक क्रिप्टिक चार और आप ढाल रहित हैं) जबकि इसके आसपास स्नप्रिंट पर लागू किया जा सकता है कोई प्रारूप ... ओह रुको स्नप्रिंट एएनएसआई सी में नहीं है। यह है (केवल?) सी 99। यह एक दूसरे को पसंद करने के लिए एक (कमजोर) कारण हो सकता है।

ठीक है। आप strncpy का भी उपयोग कर सकते हैं, है ना?

उदा

char buffer[MAX_LENGTH+1]; 
    buffer[MAX_LENGTH]=0;    // just be safe in case name is too long 
    strncpy(buffer,MAX_LENGTH,name); // strncpy will never overwrite last byte 
+0

और क्या आप सुनिश्चित हैं कि '%। * S' एएनएसआई सी में उपलब्ध है? मैंने विनिर्देश खोजने की कोशिश की है, लेकिन केवल एक (अविश्वसनीय) संदर्भ प्राप्त कर सकता है जिसने '। *' निर्दिष्ट नहीं किया है। –

+0

@Eli: सटीक (यहां के रूप में) या क्षेत्र की चौड़ाई को तारांकन के रूप में निर्दिष्ट करना मूल मानक (1 9 8 9/1 9 0 9) के बाद से एएनएसआई सी में रहा है। 'snprintf() 'सी 99 मानक में जोड़ा गया था। –

+0

@ माइकल - स्ट्रिंग ('% s') के लिए भी? यह जानना अच्छा है, धन्यवाद। –

8

प्रश्न में सरल उदाहरण के लिए, दोनों कॉल के बीच सुरक्षा में बहुत अंतर नहीं हो सकता है। हालांकि, सामान्य मामले में snprintf() शायद अधिक सुरक्षित है। एक बार आपके पास एकाधिक रूपांतरण विनिर्देशों के साथ एक अधिक जटिल प्रारूप स्ट्रिंग हो जाने के बाद यह सुनिश्चित करने के लिए कठिन (या असंभव के करीब) हो सकता है कि आपके पास बफर लंबाई अलग-अलग रूपांतरणों के लिए सटीक रूप से जिम्मेदार है - खासकर जब पिछले रूपांतरण एक निश्चित संख्या का उत्पादन नहीं करते हैं आउटपुट पात्रों का।

तो, मैं snprintf() के साथ रहूंगा।

snprintf() (हालांकि सुरक्षा से संबंधित नहीं) के लिए एक और छोटा सा फायदा यह है कि यह आपको बताएगा कि आपको बफर की कितनी बड़ी आवश्यकता है।

एक अंतिम टिप्पणी - आप snprintf() कॉल में वास्तविक बफर आकार को निर्दिष्ट करना चाहिए - यह आप के लिए अशक्त टर्मिनेटर के लिए लेखांकन संभाल लेंगे:

snprintf(buff, sizeof(buff), "%s", name); 
2

मैं snprintf() कहेंगे और अधिक बेहतर है जब तक मैंने पढ़ा है इस मार्ग:

https://buildsecurityin.us-cert.gov/bsi/articles/knowledge/coding/838-BSI.html

संक्षिप्त सारांश है: व्यवस्था करने के लिए सिस्टम से snprintf() पोर्टेबल नहीं है अपने व्यवहार में बदलाव। snprintf() के साथ सबसे गंभीर समस्या तब हो सकती है जब snprintf() को sprintf() पर कॉल करके लागू किया जाता है। आप सोच सकते हैं कि यह आपको बफर ओवरफ़्लो से बचाता है और आपकी सुरक्षा को छोड़ देता है, लेकिन ऐसा नहीं हो सकता है।

तो अब भी मैं कह रहा हूं कि snprintf() सुरक्षित है, लेकिन जब भी मैं इसका उपयोग करता हूं तो सतर्क रहना।

1

सबसे अच्छा और सबसे लचीला तरीका snprintf का उपयोग करना होगा!

size_t nbytes = snprintf(NULL, 0, "%s", name) + 1; /* +1 for the '\0' */ 
char *str = malloc(nbytes); 
snprintf(str, nbytes, "%s", name); 

C99 में, snprintf स्ट्रिंग '\0' को छोड़कर के लिए लिखा बाइट की संख्या देता है। यदि बाइट्स की आवश्यक मात्रा से कम थे, snprintf प्रारूप का विस्तार करने के लिए आवश्यक बाइट्स की संख्या लौटाता है (अभी भी '\0' को छोड़कर)। snprintf 0 लंबाई की एक स्ट्रिंग पास करके, आप समय से पहले पता लगा सकते हैं कि विस्तारित स्ट्रिंग कितनी देर तक होगी, और आवश्यक मेमोरी आवंटित करने के लिए इसका उपयोग करें।

1

इन दोनों के बीच एक महत्वपूर्ण अंतर है - snprintf कॉल सही वापसी मूल्य को समझने के लिए name तर्क (एनयूएल को समाप्त करने) को स्कैन करेगा। sprintf दूसरी ओर कॉल name से अधिकतम 255 वर्णों को पढ़ेगा।

तो अगर name के लिए सूचक है एक गैर NUL कम से कम 255 अक्षरों के साथ बफर समाप्त, snprintf कॉल बफर के अंत बंद चलाने के लिए और (जैसे कि दुर्घटनाग्रस्त के रूप में) अपरिभाषित व्यवहार ट्रिगर हो सकता है, जबकि sprintf संस्करण नहीं होगा ।

संबंधित मुद्दे