2009-11-04 23 views
15

कुछ एसक्यूएल बयान मैं एक तैयार बयान उपयोग नहीं कर सकते, उदाहरण के लिए के लिए उपयोग किए बिना एसक्यूएल स्वच्छ। क्या ऐसी उपयोगिता है जो जावा में एसक्यूएल को स्वच्छ करता है? रूबी में एक है।मैं कैसे करूँ तैयार बयान

+6

तालिका नाम आता है ** सीधे ** उपयोगकर्ता इनपुट से, आप बहुत बड़ी समस्याओं अपने एसक्यूएल sanitizing से के बारे में चिंता करने के लिए मिल गया है (और यह वहाँ को साफ़ करने में कुछ भी नहीं है नहीं है है) – ChssPly76

उत्तर

2

संभव नहीं है। String#format() का उपयोग करने के लिए आप क्या कर सकते हैं सबसे अच्छा है।

String sql = "SELECT MAX(AGE) FROM %s"; 
sql = String.format(sql, tablename); 

ध्यान दें कि यह एसक्यूएल इंजेक्शन जोखिम से बच नहीं है। यदि tablename उपयोगकर्ता/क्लाइंट-नियंत्रित मान है, तो आपको String#replaceAll() का उपयोग करके इसे sanitize करना होगा।

tablename = tablename.replaceAll("[^\\w]", ""); 

उम्मीद है कि इससे मदद मिलती है।

[संपादित करें] मुझे जोड़ना चाहिए: कॉलम मानों के लिए इसका उपयोग न करें जहां आप PreparedStatement का उपयोग कर सकते हैं। किसी भी कॉलम मानों के लिए इसे सामान्य तरीके से उपयोग करना जारी रखें।

[EDIT2] सर्वश्रेष्ठ नहीं करने के लिए उपयोगकर्ता/ग्राहक tablename जिस तरह से यह चाहते दर्ज करने में सक्षम हैं, लेकिन बेहतर उपस्थित होना होगा एक ड्रॉपडाउन ताकि यूआई में सभी वैध tablenames (आप DatabaseMetaData#getCatalogs() से प्राप्त कर सकते हैं जो) युक्त उपयोगकर्ता/ग्राहक इसे चुन सकते हैं। यदि चयन मान्य है तो सर्वर पक्ष में जांचना न भूलें क्योंकि कोई अनुरोध पैरामीटर को धोखा दे सकता है।

+0

@BalusC - एसक्यूएल इंजेक्शन संदर्भ के लिए +1। कोड मानचित्र के बारे में आपकी टिप्पणी के लिए –

0

इस मामले में आप डेटाबेस मेटाडेटा से तालिका सूची प्राप्त करके, उपलब्ध तालिकाओं की सूची के विरुद्ध तालिका नाम को सत्यापित कर सकते हैं। हकीकत में यह संभवतः रिक्त स्थान को रिक्त करने के लिए रेगेक्स का उपयोग करना आसान होगा, संभवतः कुछ एसक्यूएल आरक्षित शब्द, ";", आदि को अपने पूर्ण एसक्यूएल स्टेटमेंट बनाने के लिए कुछ झुकाव String.format का उपयोग करने से पहले स्ट्रिंग से।

कारण आप तैयार स्टेटमेंट का उपयोग नहीं कर सकते हैं क्योंकि यह शायद तालिका में नाम को घेर रहा है और इसे स्ट्रिंग की तरह से बच रहा है।

17

दाएं, तैयार कथन क्वेरी पैरामीटर का उपयोग केवल तभी किया जा सकता है जहां आप एकल अक्षर मूल्य का उपयोग करेंगे। आप तालिका नाम, कॉलम नाम, मानों की सूची, या किसी अन्य SQL वाक्यविन्यास के लिए पैरामीटर का उपयोग नहीं कर सकते हैं।

तो आपको अपने अनुप्रयोग चर को SQL स्ट्रिंग में विभाजित करना होगा और स्ट्रिंग को उचित रूप से उद्धृत करना होगा। के हवाले से अपनी मेज नाम पहचानकर्ता परिसीमित करने के लिए का उपयोग करते हैं, और यह दोगुना होकर बोली स्ट्रिंग से बच:

java.sql.DatabaseMetaData md = conn.getMetaData(); 
String q = md.getIdentifierQuoteString(); 
String sql = "SELECT MAX(AGE) FROM %s%s%s"; 
sql = String.format(sql, q, tablename.replaceAll(q, q+q), q); 

उदाहरण के लिए, यदि आपकी तालिका नाम का शाब्दिक table"name है, और अपने आरडीबीएमएस पहचानकर्ता उद्धरण कैरेक्टर "sql है, तो इस तरह की स्ट्रिंग शामिल करना चाहिए:

SELECT MAX(AGE) FROM "table""name" 

मैं भी @ ChssPly76 की टिप्पणी से सहमत - यह सबसे अच्छा है अगर आपके उपयोगकर्ता इनपुट वास्तव में शाब्दिक तालिका नाम नहीं है, लेकिन एक वाचक है कि आपके कोड एक तालिका नाम, में नक्शे आप जो फिर अंतर एसक्यूएल क्वेरी में polate। यह आपको अधिक आश्वासन देता है कि कोई एसक्यूएल इंजेक्शन नहीं हो सकता है।

HashMap h = new HashMap<String,String>(); 
/* user-friendly table name maps to actual, ugly table name */ 
h.put("accounts", "tbl_accounts123"); 

userTablename = ... /* user input */ 
if (h.containsKey(userTablename)) { 
    tablename = h.get(userTablename); 
} else { 
    throw ... /* Exception that user input is invalid */ 
} 
String sql = "SELECT MAX(AGE) FROM %s"; 
/* we know the table names are safe because we wrote them */ 
sql = String.format(sql, tablename); 
+0

+1। यह निश्चित रूप से जाने का रास्ता है। सभी टैबलेटनाम डेटाबेसमैटाडेटा # getCatalogs() द्वारा प्राप्त किए जा सकते हैं और यूआई में ड्रॉपडाउन के रूप में प्रदर्शित किए जा सकते हैं। – BalusC

+0

लेकिन यदि आप ड्रॉपडाउन में असली टेबल नाम देते हैं, तो आपको अभी भी उपयोगकर्ता इनपुट को तालिका नाम में बदलने के लिए मानचित्र का उपयोग करना चाहिए, क्योंकि इनपुट को फिक्र किया जा सकता है। जैसे ड्रॉप-डाउन में जो दिखाई देता है, उसके बावजूद मैं अनुरोध पैरामीटर में जो कुछ भी चाहता हूं उसके साथ एक यूआरएल टाइप कर सकता हूं। मानचित्र का उपयोग करना अनुरोध प्राप्त करने के बाद इनपुट फ़िल्टर करने का इरादा है, यूआई फॉर्म को आउटपुट करने से पहले नहीं। –

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